[英]Optimize SQL query in MySQL 5.6
系統是Amazon RDS(MySql 5.6.x),基於Moodle 2.8的軟件,這是我目前正在處理的表:
CREATE TABLE `mdl_course_categories` (
`id` bigint(10) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL DEFAULT '',
`idnumber` varchar(100) DEFAULT NULL,
`description` longtext,
`descriptionformat` tinyint(2) NOT NULL DEFAULT '0',
`parent` bigint(10) NOT NULL DEFAULT '0',
`sortorder` bigint(10) NOT NULL DEFAULT '0',
`coursecount` bigint(10) NOT NULL DEFAULT '0',
`visible` tinyint(1) NOT NULL DEFAULT '1',
`visibleold` tinyint(1) NOT NULL DEFAULT '1',
`timemodified` bigint(10) NOT NULL DEFAULT '0',
`depth` bigint(10) NOT NULL DEFAULT '0',
`path` varchar(255) NOT NULL DEFAULT '',
`theme` varchar(50) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `mdl_courcate_par_ix` (`parent`),
KEY `mdl_carcoute_tmid` (`timemodified`,`id`),
KEY `mdl_tm_field` (`timemodified`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
我原來的查詢是這樣的:
SELECT
id,
name,
description,
FROM_UNIXTIME(timemodified) AS timemodified,
timemodified AS traw
FROM
mdl_course_categories
WHERE
timemodified BETWEEN 1360602072 AND 1446736233
OR
id > 0
ORDER BY id ASC
LIMIT 0 , 50000
該查詢的解釋是:
+----+-------------+-----------------------+-------+----------------------------------------+---------+---------+------+------+----------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-----------------------+-------+----------------------------------------+---------+---------+------+------+----------+-------------+
| 1 | SIMPLE | mdl_course_categories | index | PRIMARY,mdl_carcoute_tmid,mdl_tm_field | PRIMARY | 8 | NULL | 68 | 100.00 | Using where |
+----+-------------+-----------------------+-------+----------------------------------------+---------+---------+------+------+----------+-------------+
數據庫專家建議我避免OR並將查詢轉換為:
SELECT * FROM
(
(
SELECT
id,
name,
description,
FROM_UNIXTIME(timemodified) AS timemodified,
timemodified AS traw
FROM
mdl_course_categories
WHERE
timemodified BETWEEN 1360602072 AND 1446736233
)
UNION ALL
(
SELECT
id,
name,
description,
FROM_UNIXTIME(timemodified) AS timemodified,
timemodified AS traw
FROM
mdl_course_categories
WHERE
id > 0
)
) t
ORDER BY id ASC
LIMIT 0 , 50000
解釋如下:
+----+--------------+-----------------------+-------+--------------------------------+-------------------+---------+------+------+----------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+--------------+-----------------------+-------+--------------------------------+-------------------+---------+------+------+----------+-----------------------+
| 1 | PRIMARY | <derived2> | ALL | NULL | NULL | NULL | NULL | 80 | 100.00 | Using filesort |
| 2 | DERIVED | mdl_course_categories | range | mdl_carcoute_tmid,mdl_tm_field | mdl_carcoute_tmid | 8 | NULL | 12 | 100.00 | Using index condition |
| 3 | UNION | mdl_course_categories | range | PRIMARY | PRIMARY | 8 | NULL | 68 | 100.00 | Using where |
| NULL | UNION RESULT | <union2,3> | ALL | NULL | NULL | NULL | NULL | NULL | NULL | Using temporary |
+----+--------------+-----------------------+-------+--------------------------------+-------------------+---------+------+------+----------+-----------------------+
你怎么看? 這可以做得更好嗎?
最佳查詢將在子查詢中包括limit
和order by
,並使用正確的索引:
SELECT *
FROM ((SELECT id, name, description,
FROM_UNIXTIME(timemodified) AS timemodified, timemodified AS traw
FROM mdl_course_categories
WHERE timemodified BETWEEN 1360602072 AND 1446736233
ORDER BY id
LIMIT 50000
) UNION ALL
(SELECT id, name, description,
FROM_UNIXTIME(timemodified) AS timemodified, timemodified AS traw
FROM mdl_course_categories
WHERE id > 0 AND
NOT timemodified BETWEEN 1360602072 AND 1446736233
ORDER BY id
LIMIT 50000
)
) t
ORDER BY id ASC
LIMIT 0 , 50000;
您想要的索引是mdl_course_categories(id, timemodified)
和mdl_course_categories(timemodified)
。 不幸的是,由於where
子句具有不等式,因此您不一定必須退出排序。 但是,排序100,000條記錄應該比所有記錄都要好。
請注意,第二個WHERE
子句已更改為從第一WHERE
句中排除記錄。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.