Einfache Postgresql libpq-code zu langsam ist?

Arbeitete ich auf postgresql mit libpq. Den unten angegebenen code nimmt eine Menge Zeit (Zeiten am Ende des Codes).

#include "stdafx.h"
#include <stdlib.h>
#include <libpq-fe.h>
#include <windows.h>

static void exit_nicely(PGconn *conn)
{
    PQfinish(conn);
    exit(1);
}

int _tmain(int argc, _TCHAR* argv[])
{
    const TCHAR *conninfo;
    PGconn     *conn;
    PGresult   *res;
    int nFields, i, j;

    if (argc > 1)
        conninfo = argv[1];
    else
        conninfo = _T("hostaddr=192.168.4.171 port=12345 dbname=mydb user=myname password=mypass");

    conn = PQconnectdb(conninfo);
    if (PQstatus(conn) != CONNECTION_OK)
    {
        fprintf(stderr, "Connection to database failed: %s",
                PQerrorMessage(conn));
        exit_nicely(conn);
    }

    /* Start a transaction block */
    res = PQexec(conn, "BEGIN");
    if (PQresultStatus(res) != PGRES_COMMAND_OK)
    {
        fprintf(stderr, "BEGIN command failed: %s", PQerrorMessage(conn));
        PQclear(res);
        exit_nicely(conn);
    }

    TCHAR szVal1[200];
    TCHAR szVal2[200];
    TCHAR szBuffer[200];

    TCHAR *paramValues[2];
    int paramLengths[2];
    int paramFormats[2] = {0,0};

    ExecStatusType eStatus;

    LARGE_INTEGER li;
    QueryPerformanceFrequency(&li);
    double dAppFreq = double(li.QuadPart)/1000.0;

    QueryPerformanceCounter(&li);
    LONGLONG siStartCounter = li.QuadPart;

    TCHAR szStmt[512] = {0};
    _tcscpy_s(szStmt, 512, _T("Insert50k"));
    Oid oidTypes[2] = {0,0};

    PGresult *pRes =    PQprepare(conn,
                        szStmt,
                        _T("insert into details values($1,$2);"),
                        2,
                        oidTypes);
    QueryPerformanceCounter(&li);
    LONGLONG siEndCounter = li.QuadPart;
    LONGLONG siLoop = 0;

    double dDiff = (siEndCounter - siStartCounter)/dAppFreq;
    printf("Prepared %.2lf\n", dDiff);

    for(int i=0; i<50000; i++)
    {
        _stprintf_s(szVal1, 200, _T("%d"), i);
        _stprintf_s(szVal2, 200, _T("Detail%d"), i);

        paramValues[0] = szVal1;
        paramValues[1] = szVal2;

        paramLengths[0] = _tcslen(szVal1);
        paramLengths[1] = _tcslen(szVal2);

        siStartCounter = siEndCounter;
        pRes = PQexecPrepared(conn,
                         szStmt,
                         2,
                         paramValues,
                         paramLengths,
                         paramFormats,
                         0);
        QueryPerformanceCounter(&li);
        siEndCounter = li.QuadPart;
        siLoop += (siEndCounter - siStartCounter);

        eStatus = PQresultStatus(res);
        if (!res ||  (eStatus != PGRES_COMMAND_OK) )
        {
            PQclear(res);
            exit_nicely(conn);
        } 
    }

    dDiff = siLoop/dAppFreq;
    printf("Inserted %.2lf\n", dDiff);

    siStartCounter = siEndCounter;


    _tcscpy_s(szBuffer,200, _T("select count(*) from programdetails;"));
    res = PQexec(conn, szBuffer);

    eStatus = PQresultStatus(res);
    if (!res ||  (eStatus != PGRES_TUPLES_OK) )
    {
        PQclear(res);
        exit_nicely(conn);
    }

    /* first, print out the attribute names */
    nFields = PQnfields(res);
    for (i = 0; i < nFields; i++)
        printf("%-15s", PQfname(res, i));
    printf("\n\n");

    /* next, print out the rows */
    for (i = 0; i < PQntuples(res); i++)
    {
        for (j = 0; j < nFields; j++)
            printf("%-15s", PQgetvalue(res, i, j));
        printf("\n");
    }

    QueryPerformanceCounter(&li);
    siEndCounter = li.QuadPart;
    dDiff = (siEndCounter - siStartCounter)/dAppFreq;
    printf("Printed %.2lf\n", dDiff);

    /* end the transaction */
    res = PQexec(conn, "COMMIT");
    PQclear(res);

    /* close the connection to the database and cleanup */
    PQfinish(conn);

    return 0;
}

Ein Beispiel für die Ausgabe (in MSEK):

Prepared 0.55
Inserted 5527.52
count

50000
Printed 7.58

Die Abfrage hier bereit ist, den ersten, und dann ausgeführt. Dieses einfache Montage dauert etwa 5,5 Sekunden. Gibt es eine bessere Möglichkeit, das gleiche zu tun oder mache ich etwas falsch hier?

  • Sie nur versuchen, zu senden 50000 Anfragen, das ist ganz normal ! Vielleicht kann man mit tune up die lib zu schicken, die ganzen Anfragen in der gleichen Zeit, das wäre schneller. Außerdem ist der server auf localhost? Wenn nicht, ein besseres Netzwerk könnte auch einen Unterschied machen.
  • War das wirklich läuft für 1,5 Stunden?
  • Die Ergebnisse sind in MSEK.
  • In diesem Fall wurde der server auf meiner eigenen Maschine. Aber es kann aus der Ferne zugegriffen werden, wie gut. Es ist auf einer 1Gbps-Verbindung. Und wie muss ich tune die lib zum senden wird die gesamte Abfrage in der gleichen Zeit? Irgendwelche Vorschläge?
  • versuchen Sie, um die Suche für die bulk-Einfügung ist das, was Sie tun wollen.
  • 1 gigabit oder 1 megabit, es spielt keine Rolle, viel, wenn kleine Pakete beteiligt sind; Ihr Hauptthema sein wird Latenz Durchsatz nicht. Sie senden jede Anfrage, dann auf eine Antwort warten, bevor weitere arbeiten. Sie können nicht tun, effizient; Sie müssen Dosierungs-Anfragen, die haben mehrere im Flug, etc. Pg nicht unterstützt mehrere gleichzeitige Anfragen (leider), aber Sie können sicher batch-oder in diesem Fall verwenden Sie COPY oder multi-row-inserts.

InformationsquelleAutor c0da | 2012-05-09
Schreibe einen Kommentar