簡體   English   中英

在MySQL 5.6中優化SQL查詢

[英]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       |
+----+--------------+-----------------------+-------+--------------------------------+-------------------+---------+------+------+----------+-----------------------+

你怎么看? 這可以做得更好嗎?

最佳查詢將在子查詢中包括limitorder 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM