How can I speed up my query?
How can I speed up this query? I use MySQL 5.1, table 'schedule' has ~ 900 K rows, and my query takes more than minute to run:
SELECT doc_code, `DATE`, time2, pat_code, STATUS,
copiedto1, copiedto2, copiedto3, copiedto4, copiedto5
FROM SCHEDULE
WHERE 1=1
AND STATUS IN (5,6,30)
AND (doc_code="K9" OR copiedto1="K9开发者_如何学Go" OR copiedto2="K9"
OR copiedto3="K9" OR copiedto4="K9" OR copiedto5="K9")
AND `date` BETWEEN "2010/04/11" AND "2011/04/11"
AND pat_code > 0
ORDER BY `date`, doc_code, time2
I experimented to add different indexes, but my query doesn't want to use any of them. Any help would be appreciated.
I would change it into
SELECT s.* FROM (
SELECT doc_code, `DATE`, time2, pat_code, STATUS,
copiedto1, copiedto2, copiedto3, copiedto4, copiedto5
FROM SCHEDULE
WHERE STATUS IN (5,6,30)
AND `date` BETWEEN "2010/04/11" AND "2011/04/11"
AND pat_code > 0
ORDER BY `date`, doc_code, time2 ) s
WHERE (s.doc_code="K9" OR s.copiedto1="K9" OR s.copiedto2="K9"
OR s.copiedto3="K9" OR s.copiedto4="K9" OR s.copiedto5="K9")
Somewhere deep in the MySQL docs I remember reading something about OR
's killing the use of indexes.
I have a feeling that is going on.
If you first do a query with all AND
's to limit the number of records
and then do the select with OR
's I hope your query will run faster.
EDIT
http://forge.mysql.com/wiki/Top10SQLPerformanceTips
Says: avoid using IN on indexed fields, it kills the performance.
Anyway, there are so many selection criteria, the query optimizer does not know where to begin.
Note that if the query optimizer 'thinks' that a criterium will use more than 25-50% (I forgot the exact percentage) of all fields, no index will be used.
Alternatively you might use
SELECT s.* FROM (
SELECT doc_code, `DATE`, time2, pat_code, STATUS,
copiedto1, copiedto2, copiedto3, copiedto4, copiedto5
FROM SCHEDULE
USE INDEX (someIndex,someOtherIndex) #<<<<-------------
WHERE STATUS IN (5,6,30)
AND `date` BETWEEN "2010/04/11" AND "2011/04/11"
AND pat_code > 0
ORDER BY `date`, doc_code, time2 ) s
WHERE (s.doc_code="K9" OR s.copiedto1="K9" OR s.copiedto2="K9"
OR s.copiedto3="K9" OR s.copiedto4="K9" OR s.copiedto5="K9")
The Index names or not equal to the fields name the index indexes.
You can find the index names in the create statement of the table, or the explain output that goes with the explain select
.
Be carefull with forcing indexes though, measure before you finalize.
And remember a forced index query that runs fast now may run slow when the data in the table(s) changes.
This is pretty optimal, did you index all of the columns in your WHERE clause?
You could try doing query in stages by prepopulating a schedule_k9 table that only has K9 codes or one that only has pat_codes > 0.
A composite index on (date, status) should make your query snappy.
SELECT doc_code, DATE, time2, pat_code, STATUS, copiedto1, copiedto2, copiedto3, copiedto4, copiedto5
FROM SCHEDULE
AND (doc_code="K9" OR copiedto1="K9" OR copiedto2="K9" OR copiedto3="K9" OR copiedto4="K9" OR copiedto5="K9")
AND pat_code > 0
AND `date` BETWEEN "2010/04/11" AND "2011/04/11"
AND STATUS IN (5,6,30)
ORDER BY `date`, doc_code, time2
I would have to see a sample of your table to improve the query even more (because there might be a lot of rows with a certain pattern etc...)
You can use a different type of mysql database. Some have better read speeds, other's have better write speeds. Here is a good article about mysql database types: here
I recommend you use the MyISAM table type. Unfortunately, it doesn't work with indexes. You can change your table's format by running this:
ALTER TABLE SCHEDUALE CHANGE TYPE=MyISAM
精彩评论