Slow queries, part 2, custom fields

Wow my users have a great sense of direction for finding slow queries -
originally the multiple-requestor-search email which is now all nice in
3.0.5, but now it seems searching for a single custom field is very very
slow - mysql spent almost 5 min (280s) ‘sending data’ and another 5 min
‘copying to tmp table’ on this

SELECT DISTINCT main.* FROM ( Tickets main LEFT JOIN
TicketCustomFieldValues as TicketCustomFieldValues_1 ON
((TicketCustomFieldValues_1.CustomField = ‘1’)) AND ( main.id =
TicketCustomFieldValues_1.Ticket)) WHERE ((main.EffectiveId = main.id))
AND ((main.Type = ‘ticket’)) AND ( ( (
(TicketCustomFieldValues_1.Content = ‘xxxxxxxxx’) ) ) ) ORDER BY
main.LastUpdated DESC LIMIT 50

seems the reason theres 2 x 5 min (sending data and the copying phase)
relates to the count(*) which runs first (causing ‘sending data’ for 5
min) which just counts the number of matches, then the actual search 5
min later causes the ‘copying to tmp table’… unpleasant as it
is, seems it might be worth doing the count() on the client over the
results by hand rather than asking poor old mysql to do something :stuck_out_tongue:

I’ve masked out the custom field value above as ‘custom field 1’ is
location and contains a site address as the value…

I appreciate the failing is not in RT particularly, but more in the
(seemingly worse and worse) handling of the query on mysql, bad analysis
and all that… this one is nice because its much more readable to
humans than the previous multi-requestor-email one…

Notably all this is only a big issue because RT locks the database
during the query, hence preventing all other activity by other users RT
sessions… i wondered before if this was alterable, I appreciate the
concurrency issues and race conditions this implies, but if the display
is written very defensively this might not have to be a problem - if the
ticket is deleted, modified etc during display, no big worry (!) just
make best effort to render something as and when you need to… things
like ACLs changing during display - again no biggie, if they previously
let you through then this is all still fine at display time, after all
if someone opened the ticket a second before the ACL change then you
cant revoke the display on their web browser that easily… or is there
a real complex issue at the heart of all this preventing you not-locking
the database for a search? Having thought about it tho i suspect my
users might just resubmit the queries over and over again until the
mysql server just becomes bogged down with a dozen of the same query
(when i kill one defective one i still have to hang around watching for
resubmissions of the query within the next 20 seconds, and shout at
people to kill web browsers if necessary)…

I’m going to do some analysis on the query, play with tables etc…
was there anything i should have upgraded in the DB from 3.0.2 to 3.0.5
(i.e. indexes) that i missed?

Iain

humans than the previous multi-requestor-email one…

Notably all this is only a big issue because RT locks the database
during the query, hence preventing all other activity by other users RT
sessions…

Can you verify that you’re using mysql 4.0.x with InnoDB tables for all
of RT’s tables?

Request Tracker... So much more than a help desk — Best Practical Solutions – Trouble Ticketing. Free.

Jesse Vincent wrote:

humans than the previous multi-requestor-email one…

Notably all this is only a big issue because RT locks the database
during the query, hence preventing all other activity by other users RT
sessions…

Can you verify that you’re using mysql 4.0.x with InnoDB tables for all
of RT’s tables?

Its a ‘custom’ compiled 4.0.13 with query logging enabled.

Table types, hmm gosh i’ll have to work out how to do that - the db was
built by the install script for rt 3.0.2
Dunno if this is right, but a mysqldump rt3 dumps create statements
ending in Type=MyISAM… i dont really know anything about table types
in mysql tho, i’d not even considered this :slight_smile: should i be changing
something? :slight_smile: (how? lol)

Thanks,
Iain

Iain Price wrote:

Table types, hmm gosh i’ll have to work out how to do that - the db was
built by the install script for rt 3.0.2

mysqlshow -i rt3

Dunno if this is right, but a mysqldump rt3 dumps create statements
ending in Type=MyISAM… i dont really know anything about table types
in mysql tho, i’d not even considered this :slight_smile: should i be changing
something? :slight_smile: (how? lol)

alter table type=innodb
(from memory)

however if you have MyISAM tables created by the RT3 install script,
your mysqld probably doesn’t have InnoDB table support. :frowning: Check
your my.cnf to make sure it’s enabled…
Phil Homewood, Systems Janitor, http://www.SnapGear.com
pdh@snapgear.com Ph: +61 7 3435 2810 Fx: +61 7 3891 3630
SnapGear - Custom Embedded Solutions and Security Appliances

Phil Homewood wrote:

Iain Price wrote:

Table types, hmm gosh i’ll have to work out how to do that - the db was
built by the install script for rt 3.0.2

mysqlshow -i rt3

Dunno if this is right, but a mysqldump rt3 dumps create statements
ending in Type=MyISAM… i dont really know anything about table types
in mysql tho, i’d not even considered this :slight_smile: should i be changing
something? :slight_smile: (how? lol)

alter table type=innodb
(from memory)

however if you have MyISAM tables created by the RT3 install script,
your mysqld probably doesn’t have InnoDB table support. :frowning: Check
your my.cnf to make sure it’s enabled…

Well that confirms its myisam tables then :stuck_out_tongue: The my.cnf file is pretty
empty on my redhat 9 box containing just a few directory locations
mainly and file locations.
Joy of having a dev box tho, i can just try the commands and stuff the
consequences :slight_smile:
OK all my tables are now innodb format… The query now takes 3 min 12
seconds (previously was between 4m30 and 5min). This will double up to
6 and a half minutes through the RT3 search cos of the count() query
first. So certainly seems to make a notable difference, and i’ll
probably go forth and gleefully turn all sorts of databases into innodb
format in the future now (any reason i shouldn’t? :P) but again although
this is a significant saving, i guess i’m looking for reducing this
search down to the order of a second or two, 3 max i’d say for what is
effectively such a simple ‘request’ so i guess I still need to make it
60 times faster still…

I’m going to do some quick (well, slow i guess) poking to see what
happens if i search for 2 values on the same custom field. Or values
from 2 custom fields. If it takes more than 10 min on a query i’ll
terminate it and log it as a ‘time out’.

Thanks for the info, any further suggestions from anyone appreciated :slight_smile:
Iain

Iain Price wrote:

I’m going to do some quick (well, slow i guess) poking to see what
happens if i search for 2 values on the same custom field. Or values
from 2 custom fields. If it takes more than 10 min on a query i’ll
terminate it and log it as a ‘time out’.

well, dunno if its useful, but searching for many values across many
fields takes pretty much the same time as searching for one value in one
custom field. Or so it seems to me :slight_smile:

Iain

Iain Price wrote:

OK all my tables are now innodb format… The query now takes 3 min 12
seconds (previously was between 4m30 and 5min). This will double up to
6 and a half minutes through the RT3 search cos of the count() query

Actually, I don’t think it should double, if you’ve enabled mysql’s
query_cache. Though I’m not 100% sure the optimiser will reuse the
cached result if there’s a count() there…

At any rate:- that’s still a very slow query. mysql’s “explain”
might give some tips on why it’s being so slow.
Phil Homewood, Systems Janitor, http://www.SnapGear.com
pdh@snapgear.com Ph: +61 7 3435 2810 Fx: +61 7 3891 3630
SnapGear - Custom Embedded Solutions and Security Appliances

Phil Homewood wrote:

Iain Price wrote:

OK all my tables are now innodb format… The query now takes 3 min 12
seconds (previously was between 4m30 and 5min). This will double up to
6 and a half minutes through the RT3 search cos of the count() query

Actually, I don’t think it should double, if you’ve enabled mysql’s
query_cache. Though I’m not 100% sure the optimiser will reuse the
cached result if there’s a count() there…

At any rate:- that’s still a very slow query. mysql’s “explain”
might give some tips on why it’s being so slow.

Yeah been chatting to someone else off-list about databases… Now i’ve
got proper query caching in place, and a ‘large’ mysql memory config
thing, the search still takes 3min 12 but at least the repetition of the
search should be near instant… but yeah these approaches aren’t
solving the problem of a badly analysed query.

Also, sadly regarding the ‘doubling’ of the search

[root@xxxxxxxxxx root]# time mysql rt3 -e “SELECT count(DISTINCT main.id) FROM ( Tickets main LEFT JOIN TicketCustomFieldValues as TicketCustomFieldValues_1 ON ((TicketCustomFieldValues_1.CustomField = ‘1’)) AND ( main.id = TicketCustomFieldValues_1.Ticket)) WHERE ((main.EffectiveId = main.id)) AND ((main.Type =‘ticket’)) AND ( ( ( (TicketCustomFieldValues_1.Content LIKE ‘%%xxxxxxxxxx%%’) ) ) )” >/dev/null
real 3m4.694s
user 0m0.004s
sys 0m0.002s

[root@xxxxxxxxxx root]# time mysql rt3 -e “SELECT DISTINCT main.* FROM ( Tickets main LEFT JOIN TicketCustomFieldValues as TicketCustomFieldValues_1 ON ((TicketCustomFieldValues_1.CustomField = ‘1’)) AND ( main.id = TicketCustomFieldValues_1.Ticket)) WHERE ((main.EffectiveId = main.id)) AND ((main.Type = ‘ticket’)) AND ( ( ( (TicketCustomFieldValues_1.Content LIKE ‘%%xxxxxxxxxx%%’) ) ) ) ORDER BY main.id ASC LIMIT 50” >/dev/null
real 3m12.915s
user 0m0.006s
sys 0m0.002s

(lol at it taking me a few seconds to realise why user/sys values are
negligable)

I.e when RT executes the query twice, once for the ‘xx results’, once to
get the results, mysql evaluates each one from scratch, even thought the
where clause on the statements is the same. I dont know if its the
aggregation count() function or the sort/limit that causes the results
to be unusable, or even the different fields searched for (one counts id
and the other returns *) - this is unfortunate - it would be nice if
mysql would cache the pre-aggregation result set - or whever causes it
this issue, but this isn’t a RDBMS analysis really - not the theory of
writing one anyway :slight_smile:

And to prove it all works, when i run it again immediately after…

[root@xxxxxxxxxx root]# time mysql rt3 -e “SELECT count(DISTINCT main.id) FROM ( Tickets main LEFT JOIN TicketCustomFieldValues as TicketCustomFieldValues_1 ON ((TicketCustomFieldValues_1.CustomField = ‘1’)) AND ( main.id = TicketCustomFieldValues_1.Ticket)) WHERE ((main.EffectiveId = main.id)) AND ((main.Type =‘ticket’)) AND ( ( ( (TicketCustomFieldValues_1.Content LIKE ‘%%xxxxxxxxxx%%’) ) ) )” >/dev/null
real 0m0.007s
user 0m0.004s
sys 0m0.004s

[root@xxxxxxxxxx root]# time mysql rt3 -e “SELECT DISTINCT main.* FROM ( Tickets main LEFT JOIN TicketCustomFieldValues as TicketCustomFieldValues_1 ON ((TicketCustomFieldValues_1.CustomField = ‘1’)) AND ( main.id = TicketCustomFieldValues_1.Ticket)) WHERE ((main.EffectiveId = main.id)) AND ((main.Type = ‘ticket’)) AND ( ( ( (TicketCustomFieldValues_1.Content LIKE ‘%%xxxxxxxxxx%%’) ) ) ) ORDER BY main.id ASC LIMIT 50” >/dev/null
real 0m0.007s
user 0m0.000s
sys 0m0.004s

Once again tests on ms-sql with these queries produces near instant results.

As for explains…

| table | type | possible_keys | key | key_len | ref | rows | Extra |
| main | range | test | test | 17 | NULL | 2286 | Using where; Using temporary; Using filesort |
| TicketCustomFieldValues_1 | index | NULL | test2 | 268 | NULL | 8651 | Using where; Using index; Distinct |

2 rows in set (0.00 sec)

oh thats with my testing index in there which made little (30 seconds)
difference to the search…

| table | type | possible_keys | key | key_len | ref | rows | Extra |
| main | ALL | NULL | NULL | NULL | NULL | 4663 | Using where; Using temporary; Using filesort |
| TicketCustomFieldValues_1 | ALL | NULL | NULL | NULL | NULL | 8447 | Using where; Distinct |
2 rows in set (0.04 sec)

without said indexes… (wow theres less rows without the index :stuck_out_tongue:
what does that mean lol) i am half hartedly hacking indexes around
especially after my last success with indexes but i still dont think
this will get it down to a reasonable search time (3-5 seconds) :expressionless:

As ever any suggestions gratefully received :slight_smile:

Thanks,
Iain

±--------------------------±-----±--------------±-----±--------±-----±-----±---------------------------------------------+
| main | ALL | NULL | NULL | NULL | NULL | 4663 | Using where; Using temporary; Using filesort |
| TicketCustomFieldValues_1 | ALL | NULL | NULL | NULL | NULL | 8447 | Using where; Distinct |
±--------------------------±-----±--------------±-----±--------±-----±-----±---------------------------------------------+
2 rows in set (0.04 sec)

This looks so very wrong. Are you sure you have any indices?

This is the results I get on a fresh installation for this:

SELECT DISTINCT main.* FROM ( Tickets main LEFT JOIN
TicketCustomFieldValues as TicketCustomFieldValues_1 ON
((TicketCustomFieldValues_1.CustomField = ‘1’)) AND ( main.id =
TicketCustomFieldValues_1.Ticket)) WHERE ((main.EffectiveId =
main.id)) AND ((main.Type = ‘ticket’)) AND ( ( (
(TicketCustomFieldValues_1.Content LIKE ‘%%xxxxxxxxxx%%’) ) ) )
ORDER BY main.id ASC LIMIT 50

It’s still not great, but its much improved.

*************************** 1. row ***************************
table: TicketCustomFieldValues_1
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 32962
Extra: Using where; Using temporary; Using filesort
*************************** 2. row ***************************
table: main
type: eq_ref
possible_keys: PRIMARY,Tickets4,Tickets5
key: PRIMARY
key_len: 4
ref: TicketCustomFieldValues_1.Ticket
rows: 1
Extra: Using where
2 rows in set (0.00 sec)

I have 11 indexes on my Tickets table. And only one on
TicketCustomFieldValues.

(Jesse, weren’t there some patches to put more indexes on TCFV? It
definitely needs some.)

I don’t have time to do actual timings, but:

This should help this particular search.

CREATE INDEX TCFV1 ON TicketCustomFieldValues (CustomField,Ticket,Content);

This should help CF display in general.

CREATE INDEX TCFV3 ON TicketCustomFieldValues (CustomField,Ticket);

If you could try those, it would be appreciated.

Also, the doubling of the %% shouldn’t be causing a problem, but you
might want to try with just a single %. It might let MySQL optimize
better.

-R

Robert Spier wrote:

±--------------------------±-----±--------------±-----±--------±-----±-----±---------------------------------------------+
| main | ALL | NULL | NULL | NULL | NULL | 4663 | Using where; Using temporary; Using filesort |
| TicketCustomFieldValues_1 | ALL | NULL | NULL | NULL | NULL | 8447 | Using where; Distinct |
±--------------------------±-----±--------------±-----±--------±-----±-----±---------------------------------------------+
2 rows in set (0.04 sec)

This looks so very wrong. Are you sure you have any indices?

Yes there are at least some indexes on tables according to show indexes;

I have 11 indexes on my Tickets table. And only one on
TicketCustomFieldValues.

I get 11 rows from “show indexes from Tickets” and one from
TicketCustomFieldValues… dunno if that corresponds to 11 indexes tho :slight_smile:

(Jesse, weren’t there some patches to put more indexes on TCFV? It
definitely needs some.)

I don’t have time to do actual timings, but:

This should help this particular search.

CREATE INDEX TCFV1 ON TicketCustomFieldValues (CustomField,Ticket,Content);

This should help CF display in general.

CREATE INDEX TCFV3 ON TicketCustomFieldValues (CustomField,Ticket);

If you could try those, it would be appreciated.

went from 3 min 51 seconds (hmm thats gone up from 3 min 12
somewhere)… to 0.38 seconds :open_mouth:

This seems to be the second time that adding indexes to RT’s databases
has reduced the search time by orders of magnitude in excess of a
thousand times faster (see my original posts regarding the multiple
requestor search)…

Did i miss something out? Should i have these indexes already - did i
miss install? or is the default RT DB schema just sadly lacking in
essential indexes? Might it be worth getting someone who is good with
indexes to review the DB? Personally i just make random indexes on
tables until my slow query gets better, but this clearly isn’t a good
approach for designing, just (blindly/ignorantly) optimizing later…
It does seem (empirically) that a few well placed indexes within RT
could do absolute wonders for its performance…

Also, the doubling of the %% shouldn’t be causing a problem, but you
might want to try with just a single %. It might let MySQL optimize
better.

Takes just as long without any % and LIKE at all using an = … (with or
without indexes)

Congratulations are in order, well nailed :wink:

Thanks,
Iain

(with that and the mod_perl 1/2 attachment issue solved, maybe i can go
back to doing my real job lol)
oh wait, i have one more issue, attachments getting lost being mailed to
rt - even with mod_perl 1 - i suspect this is a timeout in the
rt-mailgate HTTP connection as i saw that a few times during testing,
but ATM I work for two departments (and get paid for one naturally) and
i have to do work for the other department this week so this will have
to wait :slight_smile:

Ian,

Yes there are at least some indexes on tables according to show indexes;
I get 11 rows from “show indexes from Tickets” and one from
TicketCustomFieldValues… dunno if that corresponds to 11 indexes
tho :slight_smile:

Thats the same metric I used. What version of MySQL are you using?
EXPLAIN wasn’t showing all the indices it should have been.

went from 3 min 51 seconds (hmm thats gone up from 3 min 12 somewhere)… to 0.38
seconds :open_mouth:

Not bad at all.

Did i miss something out? Should i have these indexes already - did
i miss install?

No. These weren’t in the schema.

or is the default RT DB schema just sadly lacking in essential
indexes? Might it be worth getting someone who is good with indexes
to review the DB? Personally i just make random indexes on tables
until my slow query gets better, but this clearly isn’t a good
approach for designing, just (blindly/ignorantly) optimizing
later… It does seem (empirically) that a few well placed indexes
within RT could do absolute wonders for its performance…

Well… at this point RT has 95% of the indexes it neeeds. I’ve
created a ticket (#3776) which adds the two from before, and suggests
another three that looked missing to me. We’re at the point where (I
think) all the obvious indexes (will be) in place, and it makes more
sense to add new ones as slow things are found.

(To anyone:) If you have upgraded from an earlier verison of RT3, you
may want to extract all the CREATE INDEX commands from schema.Mysql
and run them. Mysql won’t let you create duplicate indexes.

Congratulations are in order, well nailed :wink:

You’re welcome.

-R

Ian

See http://www.mysql.com/newsletter/2003-01/a0000000108.html

http://www.mysql.com/doc/en/Query_Cache_How.html

Basically the Mysql book says that the queries must be :-

“exactly the same (byte for byte)”

so “select * from table” and “SELECT * FROM TABLE” are different.

Scott.-----Original Message-----
From: rt-devel-admin@lists.fsck.com [mailto:rt-devel-admin@lists.fsck.com]
On Behalf Of Iain Price Sent: Friday, 3 October 2003 8:56 PM To: Phil Homewood Cc: rt-devel@lists.fsck.com Subject: Re: [rt-devel] Slow queries, part 2, custom fields Phil Homewood wrote:

Iain Price wrote:

OK all my tables are now innodb format… The query now takes 3 min 12

seconds (previously was between 4m30 and 5min). This will double up to

6 and a half minutes through the RT3 search cos of the count() query

Actually, I don’t think it should double, if you’ve enabled mysql’s

query_cache. Though I’m not 100% sure the optimiser will reuse the

cached result if there’s a count() there…

At any rate:- that’s still a very slow query. mysql’s “explain”

might give some tips on why it’s being so slow.

Yeah been chatting to someone else off-list about databases… Now i’ve got
proper query caching in place, and a ‘large’ mysql memory config thing, the
search still takes 3min 12 but at least the repetition of the search should
be near instant… but yeah these approaches aren’t solving the problem
of a badly analysed query.

Also, sadly regarding the ‘doubling’ of the search

[root@xxxxxxxxxx root]# time mysql rt3 -e “SELECT count(DISTINCT main.id)
FROM ( Tickets main LEFT JOIN TicketCustomFieldValues as
TicketCustomFieldValues_1 ON ((TicketCustomFieldValues_1.CustomField =
‘1’)) AND ( main.id = TicketCustomFieldValues_1.Ticket)) WHERE
((main.EffectiveId = main.id)) AND ((main.Type =‘ticket’)) AND ( ( (
(TicketCustomFieldValues_1.Content LIKE ‘%%xxxxxxxxxx%%’) ) ) )” >/dev/null

real 3m4.694s

user 0m0.004s

sys 0m0.002s
[root@xxxxxxxxxx root]# time mysql rt3 -e “SELECT DISTINCT main.* FROM (
Tickets main LEFT JOIN TicketCustomFieldValues as TicketCustomFieldValues_1
ON ((TicketCustomFieldValues_1.CustomField = ‘1’)) AND ( main.id =
TicketCustomFieldValues_1.Ticket)) WHERE ((main.EffectiveId = main.id)) AND
((main.Type = ‘ticket’)) AND ( ( ( (TicketCustomFieldValues_1.Content LIKE
‘%%xxxxxxxxxx%%’) ) ) ) ORDER BY main.id ASC LIMIT 50” >/dev/null

real 3m12.915s

user 0m0.006s

sys 0m0.002s
(lol at it taking me a few seconds to realise why user/sys values are
negligable)

I.e when RT executes the query twice, once for the ‘xx results’, once to get
the results, mysql evaluates each one from scratch, even thought the where
clause on the statements is the same. I dont know if its the aggregation
count() function or the sort/limit that causes the results to be unusable,
or even the different fields searched for (one counts id and the other
returns *) - this is unfortunate - it would be nice if mysql would cache the
pre-aggregation result set - or whever causes it this issue, but this isn’t
a RDBMS analysis really - not the theory of writing one anyway :slight_smile:

And to prove it all works, when i run it again immediately after…

[root@xxxxxxxxxx root]# time mysql rt3 -e “SELECT count(DISTINCT main.id)
FROM ( Tickets main LEFT JOIN TicketCustomFieldValues as
TicketCustomFieldValues_1 ON ((TicketCustomFieldValues_1.CustomField =
‘1’)) AND ( main.id = TicketCustomFieldValues_1.Ticket)) WHERE
((main.EffectiveId = main.id)) AND ((main.Type =‘ticket’)) AND ( ( (
(TicketCustomFieldValues_1.Content LIKE ‘%%xxxxxxxxxx%%’) ) ) )” >/dev/null

real 0m0.007s

user 0m0.004s

sys 0m0.004s
[root@xxxxxxxxxx root]# time mysql rt3 -e “SELECT DISTINCT main.* FROM (
Tickets main LEFT JOIN TicketCustomFieldValues as TicketCustomFieldValues_1
ON ((TicketCustomFieldValues_1.CustomField = ‘1’)) AND ( main.id =
TicketCustomFieldValues_1.Ticket)) WHERE ((main.EffectiveId = main.id)) AND
((main.Type = ‘ticket’)) AND ( ( ( (TicketCustomFieldValues_1.Content LIKE
‘%%xxxxxxxxxx%%’) ) ) ) ORDER BY main.id ASC LIMIT 50” >/dev/null

real 0m0.007s

user 0m0.000s

sys 0m0.004s
Once again tests on ms-sql with these queries produces near instant results.

As for explains…

| table | type | possible_keys | key | key_len | ref
| rows | Extra |

| main | range | test | test | 17 | NULL
| 2286 | Using where; Using temporary; Using filesort |

| TicketCustomFieldValues_1 | index | NULL | test2 | 268 | NULL
| 8651 | Using where; Using index; Distinct |

2 rows in set (0.00 sec)

oh thats with my testing index in there which made little (30 seconds)
difference to the search…

| table | type | possible_keys | key | key_len | ref |
rows | Extra |

| main | ALL | NULL | NULL | NULL | NULL |
4663 | Using where; Using temporary; Using filesort |

| TicketCustomFieldValues_1 | ALL | NULL | NULL | NULL | NULL |
8447 | Using where; Distinct |

2 rows in set (0.04 sec)

without said indexes… (wow theres less rows without the index :stuck_out_tongue: what
does that mean lol) i am half hartedly hacking indexes around especially
after my last success with indexes but i still dont think this will get it
down to a reasonable search time (3-5 seconds) :expressionless:

As ever any suggestions gratefully received :slight_smile:

Thanks,
Iain

See http://www.mysql.com/newsletter/2003-01/a0000000108.html
http://www.mysql.com/doc/en/Query_Cache_How.html

Basically the Mysql book says that the queries must be :-
“exactly the same (byte for byte)”
so “select * from table” and “SELECT * FROM TABLE” are different.

But because RT generates most queries in a standard way, they will
tend to look the same.

On my todo list is to look at another caching system which may be more
flexible and a little closer to the RT object level. If it works,
it’ll be very cool.

-R