I wrote this query back in <[EMAIL PROTECTED]> I also suggested the alternative:
select count(*), count(case when seen_flag > 0 Then 1 else null end), count(case when recent_flag > 0 then 1 else null end) FROM dbmail_messages WHERE status < '2' and mailbox_idnr='1'; in <[EMAIL PROTECTED]> but I cannot recall if I ever profiled that with MySQL. In SQLite, it generates a plan where the database isn't touched (index only). On Mon, 2005-12-12 at 10:03 -0800, Kevin Brown wrote: > In experimenting with DBMail 2.0.7 (even with the changes I submitted > regarding the headername query, I can't get 2.1-trunk to run well > enough to work properly with both Mutt and Thunderbird), I discovered > (as perhaps some of you have) that storing changes to the attributes > is very slow when the folder has lots of messages (tens of thousands). > > 2.1.x may have fixed this, though the query in question is the same. > But in 2.0.7, the following query is responsible for the bulk of the > time spent in the update: > > SELECT 'a',COUNT(*) FROM dbmail_messages WHERE mailbox_idnr='14' > AND (status='0' OR status='1') UNION SELECT 'b',COUNT(*) FROM > dbmail_messages WHERE mailbox_idnr='14' AND (status='0' OR > status='1') AND seen_flag=1 UNION SELECT 'c',COUNT(*) FROM > dbmail_messages WHERE mailbox_idnr='14' AND (status='0' OR > status='1') AND recent_flag=1 > > (substitute any given mailbox id for '14', of course). > > > This query originates from this bit of code here in function > db_getmailbox in db.c: > > snprintf(query, DEF_QUERYSIZE, > "SELECT 'a',COUNT(*) FROM dbmail_messages WHERE mailbox_idnr='%llu' " > "AND (status='%d' OR status='%d') UNION " > "SELECT 'b',COUNT(*) FROM dbmail_messages WHERE mailbox_idnr='%llu' " > "AND (status='%d' OR status='%d') AND seen_flag=1 UNION " > "SELECT 'c',COUNT(*) FROM dbmail_messages WHERE mailbox_idnr='%llu' " > "AND (status='%d' OR status='%d') AND recent_flag=1", > mb->uid, MESSAGE_STATUS_NEW, MESSAGE_STATUS_SEEN, > mb->uid, MESSAGE_STATUS_NEW, MESSAGE_STATUS_SEEN, > mb->uid, MESSAGE_STATUS_NEW, MESSAGE_STATUS_SEEN); > > > > That query is horribly inefficient on PostgreSQL. The following is > much more efficient (by at least a factor of two if not more) and > accomplishes the same thing, though it will require a bit more > interpretation by our code to use: > > SELECT seen_flag*2 + recent_flag, count(*) FROM dbmail_messages > WHERE mailbox_idnr = '14' AND status IN ('0', '1') GROUP BY > seen_flag*2 + recent_flag; > > We can generate it thusly: > > snprintf(query, DEF_QUERYSIZE, > "SELECT seen_flag*2 + recent_flag, count(*) FROM " > "dbmail_messages WHERE mailbox_idnr = '%d' AND status IN " > "('%d', '%d') GROUP BY seen_flag*2 + recent_flag", > mb->uid, MESSAGE_STATUS_NEW, MESSAGE_STATUS_SEEN); > > The query will return up to 4 rows with the following values as the > first column: > > 0: neither seen_flag nor recent_flag is set. > 1: recent_flag is set, seen_flag is not. > 2: seen_flag is set, recent_flag is not. > 3: both seen_flag and recent_flag are set > > > The additional interpretation is in reading and interpreting the > results. The query won't return rows for flag combinations that don't > have any corresponding entries, so we have to infer those. I think > the most efficient way to do that is to create a simple 4-element > integer array, initialize its elements to zero, and use the first > column results as the index to that array. Place the results in the > array. The array will have zero for entries that weren't returned by > the query. The array definition will be something like: > > unsigned int results[4]; > > > The values we're interested in (exists, seen, recent) will then be: > > exists = results[0] + results[1] + results[2] + results[3]; > seen = results[2] + results[3]; > recent = results[1] + results[3] > > > > Now, the above is more efficient, but the real win would be if we > could avoid calling db_getmailbox (or perhaps a modified version of it > that doesn't have to do any of this) altogether after doing a STORE. > > > I don't know how much more (if any) efficient the above will be on > MySQL or SQLite, but I wouldn't expect it to be less efficient. > > > Thoughts? > > > -- Internet Connection High Quality Web Hosting http://www.internetconnection.net/