The dbmail_messages_physmessage_idx isn't the best index to use.

You have several options:

put extra columns in dbmail_physmessage that reference the message_idnr
and mailbox_idnr (and index them WITH the dbmail_physmessage.id) -- THEN
adapt the query to look for these fields (e.g. AND pm.message_idnr
BETWEEN 1 AND 417966 AND msg.message_idnr BETWEEN 1 AND 417966)

This is ugly. But it's the fastest for Pg.


Another option (probably would help other dbs too) is to use two
subselects - one on dbmail_messages and one on dbmail_physmessage. This
way, the best index for dbmail_messages can be used-

CREATE INDEX dbmail_messages_wide ON dbmail_messages
(mailbox_idnr,message_idnr,status);
CREATE INDEX dbmail_messages_wider ON dbmail_messages
(mailbox_idnr,message_idnr,status,physmessage_id);

I'd have to experiment to find out which one would generate the better
query plan -- only one of those two indexes should actually be used.

The query then should look like this:


SELECT
        a.seen_flag,
        a.answered_flag,
        a.deleted_flag,
        a.flagged_flag,
        a.draft_flag,
        a.recent_flag,
        b.internaldate,
        b.rfcsize,
        a.message_idnr

FROM (
        SELECT seen_flag,answered_flag,deleted_flag,
                flagged_flag,draft_flag,recent_flag,
                message_idnr,physmessage_id AS id
        FROM dbmail_messages
        WHERE message_idnr BETWEEN '1' AND '417966'
        AND mailbox_idnr = '81'
        AND (status = '0' OR status = '1')
        ORDER BY message_idnr ASC

) AS a JOIN (
        SELECT id,TO_CHAR(internal_date, 'YYYY-MM-DD HH24:MI:SS') AS
internaldate, rfcsize
        FROM dbmail_physmessage WHERE id IN (

                SELECT physmessage_id FROM dbmail_messages
                WHERE message_idnr BETWEEN '1' AND '417966'
                AND mailbox_idnr = '81'
                AND (status = '0' OR status = '1')
        )
) AS b USING (id);


{whew!}


On Thu, 2005-03-10 at 10:42 +0100, Thomas Mueller wrote:
> Hi,
> 
> now I have only one slow query left - unfortunately I have no idea why
> it is that slow. The mailbox contains ~1800 mails. It takes 45 seconds
> to open it:
> 
> SELECT seen_flag, answered_flag, deleted_flag, flagged_flag, draft_flag,
> recent_flag, TO_CHAR(internal_date, 'YYYY-MM-DD HH24:MI:SS' ), rfcsize,
> message_idnr FROM dbmail_messages msg, dbmail_physmessage pm WHERE pm.id
> = msg.physmessage_id AND message_idnr BETWEEN '1' AND '417966' AND
> mailbox_idnr = '81' AND status < '2' ORDER BY message_idnr ASC
> 
>  Sort  (cost=10809.69..10816.57 rows=2754 width=36) (actual
> time=44701.720..44709.281 rows=1827 loops=1)
>    Sort Key: msg.message_idnr
>    ->  Merge Join  (cost=0.00..10652.33 rows=2754 width=36) (actual
> time=205.203..44688.345 rows=1827 loops=1)
>          Merge Cond: ("outer".physmessage_id = "inner".id)
>          ->  Index Scan using dbmail_messages_physmessage_idx on
> dbmail_messages msg  (cost=0.00..24818.12 rows=2753 width=28) (actual
> time=161.471..42272.510 rows=1827 loops=1)
>                Filter: ((message_idnr >= 1::bigint) AND (message_idnr <=
> 417966::bigint) AND (mailbox_idnr = 81::bigint) AND (status < 2::smallint))
>          ->  Index Scan using dbmail_physmessage_pkey on
> dbmail_physmessage pm  (cost=0.00..3842.59 rows=73428 width=24) (actual
> time=0.050..1922.954 rows=103804 loops=1)
>  Total runtime: 44716.105 ms
> 
> 
> I have really no idea why the index scan takes 42 seconds.
> 
> I removed the BETWEEN (is that really required?) but there's no speed up.
> I'm on IRC, FreeNode network, channel #dbmail. I'd be happy to test
> queries if anyone has an idea.
> 
> 
> Thomas
-- 
Internet Connection High Quality Web Hosting
http://www.internetconnection.net/

Reply via email to