Search Postgresql Archives

Optimizing query: select ... where id = 4 and md5(...) = '...'

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hello,

in my application I'm trying to authenticate users
against a table called "users". The integer column
"id" should match, but also an md5 hash of the
"password" column (salted with a string) should match.
My authentication function (written in C, using libpq)
should return a "username" (is a varchar(200) field).

I wonder, what is faster: fetching 2 columns - the
username and the md5-result and then comparing the
md5 string against the argument in my app, like here:

punbb=> select username, md5('deadbeef' || password) from users where id = 4;
username |               md5
----------+----------------------------------
Vasja    | dcde745cc304742e26d62e683a9ecb0a
(1 row)

punbb=> explain select username, md5('deadbeef' || password) from
users where id = 4;
                               QUERY PLAN
--------------------------------------------------------------------------
Index Scan using users_pkey on users  (cost=0.00..5.95 rows=1 width=156)
  Index Cond: (id = 4)
(2 rows)

Or letting the database doing this comparison for me:

punbb=> select username from users where id = 4 and md5('deadbeef' ||
password) = 'dcde745cc304742e26d62e683a9ecb0a';
username
----------
Vasja
(1 row)

punbb=> explain select username from users where id = 4 and
md5('deadbeef' || password) = 'dcde745cc304742e26d62e683a9ecb0a';
                                             QUERY PLAN
------------------------------------------------------------------------------------------------------
Index Scan using users_pkey on users  (cost=0.00..5.95 rows=1 width=118)
  Index Cond: (id = 4)
  Filter: (md5(('deadbeef'::text || ("password")::text)) =
'dcde745cc304742e26d62e683a9ecb0a'::text)
(3 rows)

I've prepared a test case with the code listed at the
botom and have run it 1000 times, but am still unsure:

$ time perl -e 'for (1..1000) {system("./fetch-user", "APP_QUERY") and die $!}'
....
username: Vasja
....
5.038u 5.734s 0:26.29 40.9%     0+0k 0+4io 0pf+0w

$ time perl -e 'for (1..1000) {system("./fetch-user", "DB_QUERY") and die $!}'
....
username: Vasja
....
4.757u 5.890s 0:26.52 40.1%     0+0k 0+8io 0pf+0w

How does one profile PostgreSQL-queries in general?

Thank you
Alex

PS: Using Postgresql 8.1.0 (from packages) on OpenBSD/386 -current

PPS: My test program, call with APP_QUERY or DB_QUERY:

#include <err.h>
#include <stdio.h>
#include <libpq-fe.h>

#define DB_CONN_STR     "host=/var/www/tmp user=punbb dbname=punbb"
#define APP_QUERY       "select username, md5('deadbeef' || password) " \
                       "from users where id = $1"
#define DB_QUERY        "select username from users where id = $1 and " \
                       "md5('deadbeef' || password) = $2"
int
main(int argc, char *argv[])
{
       PGconn          *conn;
       PGresult        *res;
       const char      *query;
       const char      *args[2];
       unsigned        nargs;
       char            username[201];

       if (! strcmp(argv[1], "APP_QUERY")) {
               query = APP_QUERY;
               nargs = 1;
       } else if (! strcmp(argv[1], "DB_QUERY")) {
               query = DB_QUERY;
               nargs = 2;
       } else
               errx(1, "wrong usage: supply APP_QUERY or DB_QUERY");

       if ((conn = PQconnectdb(DB_CONN_STR)) == NULL)
               err(1, "Connect failed: out of memory");

       if (PQstatus(conn) != CONNECTION_OK)
               err(1, "Connect failed: %s", PQerrorMessage(conn));

       if ((res = PQprepare(conn, "sql_fetch_username",
           query, nargs, NULL)) == NULL)
               err(1, "Preparing '%s' failed: out of memory", query);

       if (PQresultStatus(res) != PGRES_COMMAND_OK)
               err(1, "Preparing statement failed: %s", PQerrorMessage(conn));

       PQclear(res);

       args[0] = "4";
       args[1] = "dcde745cc304742e26d62e683a9ecb0a";

       if ((res = PQexecPrepared(conn, "sql_fetch_username",
           nargs, args, NULL, NULL, 0)) == NULL)
               err(1, "Executing statement '%s' failed: out of memory",
                   query);

       if (PQresultStatus(res) != PGRES_TUPLES_OK)
               err(1, "Executing statement '%s' failed: %s",
                   query, PQerrorMessage(conn));
               PQclear(res);

       if (nargs == 1)
               (void) strcmp(args[1], PQgetvalue(res, 0, 1));

       fprintf(stderr, "username: %s\n", PQgetvalue(res, 0, 0));

       PQfinish(conn);
       return 0;
}


--
http://preferans.de


[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Postgresql Jobs]     [Postgresql Admin]     [Postgresql Performance]     [Linux Clusters]     [PHP Home]     [PHP on Windows]     [Kernel Newbies]     [PHP Classes]     [PHP Books]     [PHP Databases]     [Postgresql & PHP]     [Yosemite]
  Powered by Linux