2015-11-14 3 views
0

системы является Amazon RDS (MySql 5.6.x), Moodle 2.8 на основе программного обеспечения Вот таблица, что я в настоящее время работает над:Оптимизация SQL-запрос в MySQL 5.6

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 | 
+----+-------------+-----------------------+-------+----------------------------------------+---------+---------+------+------+----------+-------------+ 

Я предложил база данных специалиста, чтобы избежать или и преобразовать запрос в это:

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  | 
+----+--------------+-----------------------+-------+--------------------------------+-------------------+---------+------+------+----------+-----------------------+ 

Что вы думаете? Можно ли это сделать лучше?

ответ

0

Оптимальный запрос будет включать 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 изменен, чтобы исключить записи из первого.

+0

Я вижу, что вы используете UNION вместо UNION ALL. Я думал, что UNION медленнее из-за неявного DISTINCT? –

+0

Кроме того, объяснение возвращает по существу тот же план, что и в моей версии запроса union, так где же оптимизация? Просто для уменьшения количества обработанных записей? –

+1

@DarkoMiletic. , , Это должно быть «UNION ALL». И, да, эффективность в количестве обрабатываемых строк. –

Смежные вопросы