简体   繁体   中英

MySQL query takes a long time to run

My table is defined as following:

CREATE TABLE `tracking_info` (
 `tid` int(25) NOT NULL AUTO_INCREMENT,
 `tracking_customer_id` int(11) NOT NULL DEFAULT '0',
 `tracking_content` text NOT NULL,
 `tracking_type` int(11) NOT NULL DEFAULT '0',
 `time_recorded` int(25) NOT NULL DEFAULT '0',
 PRIMARY KEY (`tid`),
 KEY `time_recorded` (`time_recorded`),
 KEY `tracking_idx` (`tracking_customer_id`,`tracking_type`,
                     `time_recorded`,`tid`)
) ENGINE=MyISAM

The table contains about 150 million records. Here is the query:

SELECT tracking_content, tracking_type, time_recorded 
FROM tracking_info 
WHERE FROM_UNIXTIME(time_recorded) > DATE_SUB( NOW( ) , 
                    INTERVAL 90 DAY )
  AND tracking_customer_id = 111111 
ORDER BY time_recorded DESC 
LIMIT 0,10

It takes about a minute to run the query even without ORDER BY. Any thoughts? Thanks in advance!

First, refactor the query so it's sargable .

SELECT tracking_content, tracking_type, time_recorded 
FROM tracking_info 
WHERE time_recorded > UNIX_TIMESTAMP(DATE_SUB( NOW( ) , INTERVAL 90 DAY )
  AND tracking_customer_id = 111111 
ORDER BY time_recorded DESC 
LIMIT 0,10;

Then add this multi-column index:

ALTER TABLE tracking_info 
    ADD INDEX cust_time (tracking_customer_id, time_recorded DESC);

Why will this help?

  1. It compares the raw data in a column with a constant, rather than using the FROM_UNIXTIME() function to transform all the data in that column of the table. That makes the query sargable .

  2. The query planner can random-access the index I suggest to the first eligible row, then read ten rows sequentially from the index and look up what it needs from the table, then stop.

You can rephrase the query to isolate time_recorded , as in:

SELECT tracking_content, tracking_type, time_recorded 
FROM tracking_info 
WHERE time_recorded > UNIX_TIMESTAMP(DATE_SUB(NOW(), INTERVAL 90 DAY))
  AND tracking_customer_id = 111111 
ORDER BY time_recorded DESC 
LIMIT 0,10

Then, the following index will probably make the query faster:

create index ix1 on tracking_info (tracking_customer_id, time_recorded);

There are 3 things to do:

  • Change to InnoDB.

  • Add INDEX(tracking_customer_id, time_recorded)

  • Rephrase to time_recorded > NOW() - INTERVAL 90 DAY)

Non-critical notes:

  • int(25) -- the "25" has no meaning. You get a 4-byte signed number regardless.
  • There are datatypes DATETIME and TIMESTAMP ; consider using one of them instead of an INT that represents seconds since sometime. (It would be messy to change, so don't bother.)
  • When converting to InnoDB, the size on disk will double or triple.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM