On Wed, 2005-03-09 at 11:51 +0100, Thomas Mueller wrote:
> Hi,
> 
> I get more and more user complaints that my IMAP server is terrible
> slow, opening a mailbox takes very long.
> 
> I've analyzed that using PQA (http://pgfoundry.org/projects/pqa/, great
> tool!), the output is attached if anyone is interested (includes all
> databases, not only dbmail).
> 
> The main problem is in db.c, db_getmailbox():
> SELECT COUNT(message_idnr), COUNT(message_idnr) - SUM(seen_flag),
> SUM(recent_flag) FROM dbmail_messages WHERE mailbox_idnr = '5' AND
> status < '2'
> That query takes up to 15 seconds (!!).

A better query would be:

SELECT COUNT(*) FROM dbmail_messages WHERE mailbox_idnr='5' AND
(status='0' OR status='1') UNION
SELECT COUNT(*) FROM dbmail_messages WHERE mailbox_idnr='5' AND
(status='0' OR status='1') AND seen_flag=1 UNION
SELECT COUNT(*) FROM dbmail_messages WHERE mailbox_idnr='5' AND
(status='0' OR status='1') AND recent_flag=1;

Then having the following indexes:
        mailbox_idnr
        mailbox_idnr,status
        mailbox_idnr,status,seen_flag
        mailbox_idnr,status,recent_flag

Then having an index on mailbox_idnr AND status will mean we never have
to look at the database contents to answer the query (only examining the
index.

If you feel REALLY wary about using UNION- make union-ability a flag and
do each query separately if the backend says it can't do UNION.

We should also include the following indexes:
        mailbox_idnr,message_idnr,status
        mailbox_idnr,message_idnr

with SQLite, this plan never touches the records (only the index) - even
though the plain is much longer (139 ops instead of 57) it's SO MUCH
faster.

It would take [me] some time to actually test this with PgSQL - and I'll
do that if someone who has an active dbmail+pg complains.


BTW: I added this to my sql/sqlite/create_tables.sqlite for this.

CREATE INDEX dbmail_messages_7 ON dbmail_messages
(mailbox_idnr,status,seen_flag);
CREATE INDEX dbmail_messages_8 ON dbmail_messages
(mailbox_idnr,status,recent_flag);


> Obviously that doesn't scale at all - dbmail is not usable on PostgreSQL
> with lot of mails and/or users.
> 
> If I replace COUNT(message_idnr) with the value I get the query is about
> 30 (!) times faster and takes about 0.4 seconds:
> 
> SELECT 611, 611 - SUM(seen_flag), SUM(recent_flag) FROM dbmail_messages
> WHERE mailbox_idnr = '5' AND status < '2';
> 
> So the solution is easy: add a row to dbmail_mailboxes that contains the
> number of messages. The row is updated by a trigger when messages are
> inserted or deleted. That is a quick and easy fix (only one query in the
> dbmail code has to be changed) - but that doesn't work for MySQL, I know :-/

I do not think this would work as well as you think this would work.


> I think in this case database abstraction simply doesn't work. We have
> to use two different queries in the code, but I might be wrong. Does
> anyone have a better solution?
> 
> 
> Thomas
> HTML page attachment (pg.html)
> SQL Query Analysis (generated Wed Mar 09 09:14:24 CET 2005)
> 
> 
> ______________________________________________________________________
>                                                Reports
>                           Overall statistics
>                            Queries by type
>                   Queries that took up the most time
>                            Slowest queries
>                         Most frequent queries
>                                    
> ______________________________________________________________________
> Overall statistics
> 375375 queries 
> 262 unique queries 
> Total query duration was 7389.75 seconds 
> Longest query (SELECT pnd."SeqId",pnd."TableName",
> pnd."Op",pnddata."IsKey", pnddata."Data" AS "Data" FROM "Pending" pnd,
> "PendingData" pnddata WHERE pnd."SeqId" = pnddata."SeqId" AND
> pnd."XID"={ } ORDER BY "SeqId", "IsKey" DESC) ran in 84.216 seconds 
> Shortest query (SET DATESTYLE = ISO) ran in 0.000 seconds 
> Log file parsed in 358.1 seconds 
> Queries by type
>          Type
>          Count
>       Percentage
> SELECT
> 306035
>           82
> INSERT
> 46531
>           12
> UPDATE
> 10028
>            3
> DELETE
> 10415
>            3
> Queries that took up the most time
>       Rank
>    Total time
>     (seconds)
>  Times executed
>    Query text
> 1
> 2532.248
>              9593
> SELECT COUNT
> (message_idnr),
> COUNT
> (message_idnr) -
> SUM(seen_flag),
> SUM(recent_flag)
> FROM
> dbmail_messages
> WHERE
> mailbox_idnr =
> { } AND status <
> { }
> 2
> 1398.038
>              9526
> SELECT
> message_idnr FROM
> dbmail_messages
> WHERE
> mailbox_idnr =
> { } AND status <
> { } ORDER BY
> message_idnr ASC
> 3
> 515.294
>              9933
> INSERT INTO
> "PendingData" ("SeqId","IsKey","Data") VALUES(currval({ }),{ },$1)
> 4
> 340.673
>                32
> SELECT
> filename,md5sum,size,mtime FROM filelist WHERE owner={ } AND filename LIKE { 
> } EXCEPT SELECT filename,md5sum,size,mtime FROM filelist WHERE owner={ } AND 
> filename LIKE { } ORDER BY filename ASC LIMIT { } OFFSET { }
> 5
> 312.432
>              3375
> select
> a.oid,a.relname,a.relnamespace,a.relpages,a.relisshared,a.reltuples,b.schemaname,b.n_tup_ins,b.n_tup_upd,b.n_tup_del
>  from pg_class a, pg_stat_all_tables b where a.oid=b.relid and a.relkind = { 
> } and schemaname not like { }
> 6
> 302.986
>              1815
> SELECT seen_flag,
> answered_flag,
> deleted_flag,
> flagged_flag,
> draft_flag,
> recent_flag,
> TO_CHAR
> (internal_date,
> { } ), rfcsize,
> message_idnr FROM
> dbmail_messages
> msg,
> dbmail_physmessage pm WHERE pm.id = msg.physmessage_id AND message_idnr 
> BETWEEN { } AND { } AND mailbox_idnr = { } AND status < { } ORDER BY 
> message_idnr ASC
> 7
> 209.489
>              8932
> INSERT INTO
> "MirroredTransaction" ("XID","LastSeqId","MirrorHostId") VALUES ({ },{ },{ })
> 8
> 202.152
>             41707
> SELECT messageblk
> FROM
> dbmail_messageblks blk, dbmail_messages msg WHERE blk.physmessage_id = 
> msg.physmessage_id AND msg.message_idnr = { } ORDER BY blk.messageblk_idnr 
> ASC LIMIT { }
> 9
> 198.843
>              8932
> DELETE FROM
> "Pending" WHERE
> "XID"={ } AND
> (SELECT COUNT(*)
> FROM
> "MirroredTransaction" WHERE "XID"={ })=(SELECT COUNT(*) FROM "MirrorHost")
> 10
> 196.429
>              8988
> SELECT
> pnd."SeqId",pnd."TableName", pnd."Op",pnddata."IsKey", pnddata."Data" AS 
> "Data" FROM "Pending" pnd, "PendingData" pnddata WHERE pnd."SeqId" = 
> pnddata."SeqId" AND pnd."XID"={ } ORDER BY "SeqId", "IsKey" DESC
> 11
> 111.962
>              9068
> SELECT DISTINCT
> name FROM
> tmm_customer_domains WHERE name={ }
> 12
> 73.809
>              3837
> SELECT MIN
> (message_idnr)
> FROM
> dbmail_messages
> WHERE
> mailbox_idnr =
> { } AND status <
> { } AND seen_flag
> = { }
> 13
> 70.220
>              1884
> commit
> 14
> 65.325
>              5948
> SELECT
> block.messageblk
> FROM
> dbmail_messageblks block, dbmail_messages msg WHERE block.physmessage_id = 
> msg.physmessage_id AND msg.message_idnr = { } ORDER BY block.messageblk_idnr
> 15
> 60.511
>             45277
> select
> content,ttl,prio,type,domain_id,name from records where type={ } and name={ }
> Slowest queries
>          Rank
>          Time
>       Query text
> 1
> 84.216
> SELECT
> pnd."SeqId",pnd."TableName", pnd."Op",pnddata."IsKey", pnddata."Data" AS 
> "Data" FROM "Pending" pnd, "PendingData" pnddata WHERE pnd."SeqId" = 
> pnddata."SeqId" AND pnd."XID"={ } ORDER BY "SeqId", "IsKey" DESC
> 2
> 81.209
> SELECT
> pnd."SeqId",pnd."TableName", pnd."Op",pnddata."IsKey", pnddata."Data" AS 
> "Data" FROM "Pending" pnd, "PendingData" pnddata WHERE pnd."SeqId" = 
> pnddata."SeqId" AND pnd."XID"={ } ORDER BY "SeqId", "IsKey" DESC
> 3
> 57.863
> SELECT seen_flag,
> answered_flag,
> deleted_flag,
> flagged_flag,
> draft_flag,
> recent_flag, TO_CHAR
> (internal_date, { } ),
> rfcsize, message_idnr
> FROM dbmail_messages
> msg, dbmail_physmessage
> pm WHERE pm.id =
> msg.physmessage_id AND
> message_idnr BETWEEN
> { } AND { } AND
> mailbox_idnr = { } AND
> status < { } ORDER BY
> message_idnr ASC
> 4
> 45.004
> SELECT seen_flag,
> answered_flag,
> deleted_flag,
> flagged_flag,
> draft_flag,
> recent_flag, TO_CHAR
> (internal_date, { } ),
> rfcsize, message_idnr
> FROM dbmail_messages
> msg, dbmail_physmessage
> pm WHERE pm.id =
> msg.physmessage_id AND
> message_idnr BETWEEN
> { } AND { } AND
> mailbox_idnr = { } AND
> status < { } ORDER BY
> message_idnr ASC
> 5
> 37.403
> SELECT seen_flag,
> answered_flag,
> deleted_flag,
> flagged_flag,
> draft_flag,
> recent_flag, TO_CHAR
> (internal_date, { } ),
> rfcsize, message_idnr
> FROM dbmail_messages
> msg, dbmail_physmessage
> pm WHERE pm.id =
> msg.physmessage_id AND
> message_idnr BETWEEN
> { } AND { } AND
> mailbox_idnr = { } AND
> status < { } ORDER BY
> message_idnr ASC
> 6
> 32.138
> SELECT seen_flag,
> answered_flag,
> deleted_flag,
> flagged_flag,
> draft_flag,
> recent_flag, TO_CHAR
> (internal_date, { } ),
> rfcsize, message_idnr
> FROM dbmail_messages
> msg, dbmail_physmessage
> pm WHERE pm.id =
> msg.physmessage_id AND
> message_idnr BETWEEN
> { } AND { } AND
> mailbox_idnr = { } AND
> status < { } ORDER BY
> message_idnr ASC
> 7
> 29.513
> SELECT seen_flag,
> answered_flag,
> deleted_flag,
> flagged_flag,
> draft_flag,
> recent_flag, TO_CHAR
> (internal_date, { } ),
> rfcsize, message_idnr
> FROM dbmail_messages
> msg, dbmail_physmessage
> pm WHERE pm.id =
> msg.physmessage_id AND
> message_idnr BETWEEN
> { } AND { } AND
> mailbox_idnr = { } AND
> status < { } ORDER BY
> message_idnr ASC
> 8
> 28.300
> SELECT seen_flag,
> answered_flag,
> deleted_flag,
> flagged_flag,
> draft_flag,
> recent_flag, TO_CHAR
> (internal_date, { } ),
> rfcsize, message_idnr
> FROM dbmail_messages
> msg, dbmail_physmessage
> pm WHERE pm.id =
> msg.physmessage_id AND
> message_idnr BETWEEN
> { } AND { } AND
> mailbox_idnr = { } AND
> status < { } ORDER BY
> message_idnr ASC
> 9
> 20.188
> SELECT usr.user_idnr,
> sum(pm.messagesize),
> usr.curmail_size FROM
> dbmail_users usr LEFT
> JOIN dbmail_mailboxes
> mbx ON mbx.owner_idnr =
> usr.user_idnr LEFT JOIN
> dbmail_messages msg ON
> msg.mailbox_idnr =
> mbx.mailbox_idnr LEFT
> JOIN dbmail_physmessage
> pm ON pm.id =
> msg.physmessage_id AND
> msg.status < { } GROUP
> BY usr.user_idnr,
> usr.curmail_size HAVING
> ((SUM(pm.messagesize)
> <> usr.curmail_size) OR
> (NOT (SUM
> (pm.messagesize) IS NOT
> NULL) AND
> usr.curmail_size <>
> { }))
> 10
> 19.975
> DELETE FROM
> net_packets_raw WHERE
> timestamp < { }
> 11
> 17.378
> SELECT
> filename,md5sum,size,mtime FROM filelist WHERE owner={ } AND filename LIKE { 
> } EXCEPT SELECT filename,md5sum,size,mtime FROM filelist WHERE owner={ } AND 
> filename LIKE { } ORDER BY filename ASC LIMIT { } OFFSET { }
> 12
> 15.587
> SELECT COUNT
> (message_idnr), COUNT
> (message_idnr) - SUM
> (seen_flag), SUM
> (recent_flag) FROM
> dbmail_messages WHERE
> mailbox_idnr = { } AND
> status < { }
> 13
> 15.554
> SELECT message_idnr
> FROM dbmail_messages
> WHERE mailbox_idnr =
> { } AND status < { }
> ORDER BY message_idnr
> ASC
> 14
> 15.186
> SELECT
> filename,md5sum,size,mtime FROM filelist WHERE owner={ } AND filename LIKE { 
> } EXCEPT SELECT filename,md5sum,size,mtime FROM filelist WHERE owner={ } AND 
> filename LIKE { } ORDER BY filename ASC LIMIT { } OFFSET { }
> 15
> 14.212
> SELECT
> filename,md5sum,size,mtime FROM filelist WHERE owner={ } AND filename LIKE { 
> } EXCEPT SELECT filename,md5sum,size,mtime FROM filelist WHERE owner={ } AND 
> filename LIKE { } ORDER BY filename ASC LIMIT { } OFFSET { }
> Most frequent queries
>          Rank
>     Times executed
>       Query text
> 1
> 45277
> select
> content,ttl,prio,type,domain_id,name from records where type={ } and name={ }
> 2
> 41707
> SELECT messageblk FROM
> dbmail_messageblks blk,
> dbmail_messages msg
> WHERE
> blk.physmessage_id =
> msg.physmessage_id AND
> msg.message_idnr = { }
> ORDER BY
> blk.messageblk_idnr ASC
> LIMIT { }
> 3
> 22776
> SELECT no_select FROM
> dbmail_mailboxes WHERE
> mailbox_idnr = { }
> 4
> 20731
> INSERT INTO
> "PendingData" ("SeqId","IsKey","Data") VALUES(currval({ }),{ },$1)
> 5
> 19014
> SELECT owner_idnr FROM
> dbmail_mailboxes WHERE
> mailbox_idnr = { }
> 6
> 18917
> SELECT no_inferiors
> FROM dbmail_mailboxes
> WHERE mailbox_idnr =
> { }
> 7
> 18917
> SELECT name FROM
> dbmail_mailboxes WHERE
> mailbox_idnr = { }
> 8
> 16366
> SELECT mailbox_idnr
> FROM dbmail_mailboxes
> WHERE mailbox_idnr =
> { } AND owner_idnr =
> { }
> 9
> 12984
> INSERT INTO
> "Pending" ("TableName","Op","XID") VALUES ($1,$2,$3)
> 10
> 9593
> SELECT COUNT
> (message_idnr), COUNT
> (message_idnr) - SUM
> (seen_flag), SUM
> (recent_flag) FROM
> dbmail_messages WHERE
> mailbox_idnr = { } AND
> status < { }
> 11
> 9593
> SELECT message_idnr +
> { } FROM
> dbmail_messages ORDER
> BY message_idnr DESC
> LIMIT { }
> 12
> 9593
> SELECT
> permission,seen_flag,answered_flag,deleted_flag,flagged_flag,recent_flag,draft_flag
>  FROM dbmail_mailboxes WHERE mailbox_idnr = { }
> 13
> 9526
> SELECT message_idnr
> FROM dbmail_messages
> WHERE mailbox_idnr =
> { } AND status < { }
> ORDER BY message_idnr
> ASC
> 14
> 9154
> SELECT indkey FROM
> pg_index WHERE
> indisprimary={ } AND
> indrelid={ }
> 15
> 9068
> SELECT DISTINCT name
> FROM
> tmm_customer_domains
> WHERE name={ }
> _______________________________________________
> Dbmail-dev mailing list
> Dbmail-dev@dbmail.org
> http://twister.fastxs.net/mailman/listinfo/dbmail-dev
-- 
Internet Connection High Quality Web Hosting
http://www.internetconnection.net/

Reply via email to