Acelere o carregamento de grandes volumes no PostgreSQL usando COPY do binário STDIN

Prefácio





Estou aprendendo PostgreSQL em casa e gosto muito de processar grandes quantidades de dados. Estou escrevendo em C / C ++ no framework Qt. Infelizmente, o driver Qt Post não suporta a funcionalidade necessária para um carregamento rápido. Portanto, escrevi minha biblioteca em C ++ para isso e agora quero compartilhar com vocês este método maravilhoso de adição e a própria biblioteca.









Olá $ username!





Hoje falaremos sobre carregamento rápido de dados no DBMS PostgreSQL (doravante denominado `postik`). Faremos isso através do mecanismo COPY com a transferência de dados pela rede em formato binário.









Em primeiro lugar, considere as vantagens deste método de adição:





  • Velocidade de adição muito rápida





    Tudo se deve ao fato de que eliminamos ao mínimo a necessidade de processamento de dados (várias transformações), o post só tem que verificar se estamos usando o formato correto.





  • Não perdemos dados, ao contrário do formato de texto.





    Por exemplo, como isso pode acontecer com um número duplo. Não precisamos descobrir quantos dígitos antes e depois do ponto decimal neste método. Os dados são transmitidos "como estão".









Neste post não vou divulgar todos os detalhes que estão descritos na documentação. Vamos apenas escrever um método de adição fácil, ou seja, sem especificações e outras coisas. Todas as funções que serão chamadas no código são funções da biblioteca “libpq-fe.h”. Além disso, todo o código será escrito em C / C ++.





Algoritmo para criar um buffer binário

Estrutura do buffer:





[cabeçalho de início do buffer]





{string de dados}





{string de dados}





{string de dados}





... ... ...





{string de dados}





[ ]













:





  • 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