[英]Why would a simple MySQL update query occasionally take several minutes?
[英]Why would a MySQL SELECT query take 1-2 minutes to run if EXPLAIN only shows 400 rows?
我需要從一個大表(70M行)中獲取最近的1000條記錄,通過兩個簡單和小表上的INNER JOIN匹配幾個索引良好的項目。
查詢需要1-2分鍾才能運行。 然而, explain
只顯示了幾百行。 是什么賦予了?
如何優化查詢或更有效地索引表以使此查詢以我期望的毫秒運行?
表格:
score 70,000,000 records
class 400 records
category 400 records
查詢:
SELECT
s.log_id,
s.category_id
FROM
score s
INNER JOIN category ca ON s.category_id = ca.id
INNER JOIN class cl ON ca.class_id = cl.id
WHERE
s.score_status_type_id = 0
AND ca.category_status_id = 1
AND cl.class_status_id IN (1, 2)
AND s.date > DATE_ADD(NOW(), INTERVAL -1440 minute)
GROUP BY s.log_id
ORDER BY s.date DESC
LIMIT 1000:
這是解釋:
*** row 1 ***
table: cl
type: range
possible_keys: PRIMARY,class_status_id
key: class_status_id
key_len: 4
ref: NULL
rows: 36
Extra: Using where; Using index; Using temporary; Using filesort
*** row 2 ***
table: ca
type: ref
possible_keys: PRIMARY,class_id,category_status_id,category_status_id_class_id_id
key: category_status_id_class_id_id
key_len: 8
ref: const,my_db.cl.id
rows: 1
Extra: Using index
*** row 3 ***
table: s
type: ref
possible_keys: unique_key,category_id,date,score,score_status_type_id,score_status_and_date,category_id_score_status_type_id_date_log_id,date_reverse,category_id_date_reverse,score_date
key: category_id_score_status_type_id_date_log_id
key_len: 8
ref: my_db.ca.id,const
rows: 396
Extra: Using where; Using index
以下是一些創建表:
CREATE TABLE `score` (
`log_id` bigint(20) NOT NULL,
`profile_id` bigint(20) DEFAULT NULL,
`date` datetime DEFAULT NULL,
`class_id` int(11) NOT NULL,
`score` float(10,6) DEFAULT NULL,
`score_date` datetime DEFAULT NULL,
`process_date` datetime DEFAULT NULL,
`status_type_id` int(3) NOT NULL DEFAULT '0',
`date_reverse` int(11) DEFAULT NULL,
UNIQUE KEY `unique_key` (`log_id`,`class_id`),
KEY `class_id` (`class_id`),
KEY `profile_id` (`profile_id`),
KEY `date` (`date`),
KEY `score` (`score`),
KEY `status_type_id` (`status_type_id `),
KEY `status_type_id_date` (`status_type_id`,`date`),
KEY `class_status_type_id_date_log_id` (`class_id`,`status_type_id`,`date`,`log_id`),
KEY `date_reverse` (`date_reverse`),
KEY `class_id_date_reverse` (`class_id`,`date_reverse`),
KEY `date` (`date`),
KEY `class_id_date_reverse_log_id` (`class_id`,`date_reverse`,`log_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
CREATE TABLE `category` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`class_id` int(11) NOT NULL,
`category_status_id` int(11) NOT NULL DEFAULT '0',
`name` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`id`),
KEY `class_id` (`class_id`),
KEY `name` (`name`),
KEY `category_status_id_class_id_id` (`category_status_id`,`class_id`,`id`)
) ENGINE=InnoDB AUTO_INCREMENT=412 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
CREATE TABLE `class` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`class_status_id` int(11) NOT NULL DEFAULT '1',
`name` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`id`),
KEY `person_id` (`person_id`),
KEY `name` (`name`),
KEY `class_status_id` (`class_status_id`),
KEY `class_multi_1` (`class_status_id`,`name`,`id`)
) ENGINE=InnoDB AUTO_INCREMENT=407 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
問題是where
子句是在創建連接之后應用的過濾器 ,因此在where子句中的連接表條件要求實際連接並將其放入臨時結果集(可能很大) 。 通常,優化器會識別條件可以在連接時斷言,但有時它可能有點密集,所以......
嘗試將非鍵條件移動到連接中
SELECT s.log_id, s.category_id
FROM score s
JOIN category ca ON s.category_id = ca.id
AND ca.category_status_id = 1
JOIN class cl ON ca.class_id = cl.id
AND cl.class_status_id IN (1, 2)
WHERE s.score_status_type_id = 0
AND s.date > DATE_ADD(NOW(), INTERVAL -1440 minute)
GROUP BY s.log_id
ORDER BY s.date DESC
LIMIT 1000
如果沒有足夠的幫助, 首先嘗試抓住的子score
行作為一個子查詢, 然后做你的加入到這一點。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.