Accélérez le chargement de gros volumes dans PostgreSQL en utilisant COPY from STDIN binary

Préface





J'apprends PostgreSQL à la maison et j'aime vraiment traiter de grandes quantités de données. J'écris en C / C ++ sur le framework Qt. Malheureusement, le pilote Qt post ne prend pas en charge les fonctionnalités requises pour un chargement rapide. Par conséquent, j'ai écrit ma bibliothèque en C ++ pour cela, et maintenant je veux partager avec vous cette merveilleuse méthode d'ajout et la bibliothèque elle-même.









Bonjour $ username!





Aujourd'hui, nous allons parler du chargement rapide des données dans le SGBD PostgreSQL (ci-après dénommé «postik»). Nous le ferons via le mécanisme COPY avec le transfert de données sur le réseau dans un format binaire.









Tout d'abord, considérez les avantages de cette méthode d'ajout:





  • Vitesse d'ajout très rapide





    Tout est dû au fait que nous supprimons au minimum le besoin de traitement des données (diverses transformations), la publication n'a qu'à vérifier si nous utilisons le bon format.





  • Nous ne perdons pas de données, contrairement au format texte.





    Par exemple, comment cela peut-il arriver avec un double nombre. Nous n'aurons pas besoin de déterminer le nombre de chiffres avant et après la virgule décimale dans cette méthode. Les données sont transmises «telles quelles».









Dans cet article, je ne divulguerai pas tous les détails décrits dans la documentation. Nous allons simplement écrire une méthode d'ajout facile, c'est-à-dire sans détails et autres choses. Toutes les fonctions qui seront appelées dans le code sont des fonctions de la bibliothèque «libpq-fe.h». De plus, tout le code sera écrit en C / C ++.





Algorithme de création d'un tampon binaire

Structure du tampon:





[en-tête de démarrage du tampon]





{chaîne de données}





{chaîne de données}





{chaîne de données}





... ... ...





{chaîne de données}





[ ]













:





  • COPY-





'P','G','C','O','P','Y','\n','\377','\r','\n','\0'
      
      







'\0','\0','\0','\0'
      
      



, OID – 16- 1









'\0','\0','\0','\0'
      
      



, . , .









  • ( 13.1 ), .













:









int16_t , , . , , , .





  • :





    1)





    , ,





    2)









, :





.





int64_t , . ( ). , - . , COPY TO



, .













0xff, 0xff
      
      



. , — , ( -1).





  • , —





string conninfo = 
  "host=127.0.0.1 port=5432 dbname=postgres user=postgres password=postgres connect_timeout=10";
PGconn *conn = PQconnectdb(conninfo.c_str());
// conninfo -     ( connect_timeout    )

      
      



  • COPY-





pg_result *res = PQexec(conn, cquery);
      
      



cquery COPY . COPY testtable5 ( col1, col2, col3, col4 ) FROM STDIN (format binary);















PQputCopyData(conn, buf, currentSize);
      
      



, buf – , currentSize — .









, . . 2-128 .





  • ,





PQputCopyEnd(conn, NULL);
      
      







!





.





? , int16_t tmp = 2;



: 0x02, 0x00



0x00, 0x02



. . SPARC . , SPARC-, ( )





.

Qt:





db.open();
QSqlQuery query(db);
query.prepare("insert into testtable5 ( col1, col2, col3, col4 ) values (?,?,?,?);");
for(int i=0; i<20000000; i++)
{
    query.addBindValue("column1");
    query.addBindValue(double(12983712987.4383453947384734853872837));
    query.addBindValue(int(12345678));
    query.addBindValue(float(123.4567));
    query.exec();
}
      
      







( ) 10.000 - Y, - - X.









COPY INSERT .





- INSERT- .





- INSERT- .





- COPY- .





- COPY- .





INSERT .





- INSERT- .





- INSERT- .





COPY .





- COPY- .





- COPY- .





.





:





10.000 ( ), :





12.620 INSERT





12.050 INSERT





150 COPY





120 COPY





... COPY. , .





— . , , , .





GitHub





COPY









P.S.: , .





.








All Articles