Рассматривая план запроса EXPLAIN
, как определить, какие оптимизации лучше всего сделать?
Я ценю, что одна из первых вещей, которые нужно проверить, заключается в том, используются ли хорошие индексы, но помимо этого я немного тупик. Посредством проб и ошибок в прошлом я иногда обнаружил, что порядок, в котором проводятся объединения, может быть хорошим источником улучшения, но как можно определить, что от просмотра плана выполнения?
В то время как я очень хотел бы получить хорошее общее представление о том, как оптимизировать запросы (предлагаемое чтение очень ценится!), я также понимаю, что часто легче обсуждать конкретные случаи, чем говорить абстрактно. Поскольку я в настоящее время стучу головой о стену с этим, ваши мысли будут очень благодарны:
id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE S const PRIMARY,l,p,f4 PRIMARY 2 const 1 Using temporary 1 SIMPLE Q ref PRIMARY,S S 2 const 204 Using index 1 SIMPLE V ref PRIMARY,n,Q Q 5 const,db.Q.QID 6 Using where; Using index; Distinct 1 SIMPLE R1 ref PRIMARY,L L 154 const,db.V.VID 447 Using index; Distinct 1 SIMPLE W eq_ref PRIMARY,w PRIMARY 5 const,db.R.RID,const 1 Using where; Distinct 1 SIMPLE R2 eq_ref PRIMARY,L PRIMARY 156 const,db.W.RID,const 1 Using where; Distinct
Я правильно интерпретирую заключительную строку плана выполнения следующим образом:
- поскольку он полностью совпадает с его первичным ключом, требуется только одна строка
R2
для каждой строки вывода; - однако, такие выходные строки затем фильтруются на основе некоторых критериев, которые применяются к
R2
?
Если это так, моя проблема заключается в фильтрации, которая происходит на этом заключительном этапе. Если условие не приводит к фильтрации (например, WHERE `Col_1_to_3` IN (1,2,3)
), запрос выполняется очень быстро (~ 50 мс); однако, если условие ограничивает выбранные строки (WHERE `Col_1_to_3` IN (1,2)
), запрос занимает значительно больше времени (~ 5 с). Если ограничение на одно совпадение (WHERE `Col_1_to_3` IN (1)
), оптимизатор предлагает совсем другой план выполнения (который работает чуть лучше 5 с, но все же намного хуже 50 мс). Кажется, что нет лучшего индекса, который можно использовать в этой таблице (если он уже полностью использует первичный ключ для возврата одной строки на результат?).
Как интерпретировать всю эту информацию? Имею ли я право догадываться, что, поскольку такая фильтрация выходных данных происходит в финальной таблице, которая должна быть объединена, значительные усилия тратятся впустую против присоединения к таблице раньше и фильтрации таких строк раньше? Если да, то как определить, когда в план выполнения R2
следует соединить?
В то время как я сопротивлялся, включая запрос и схему, полностью здесь (так как я действительно мог бы знать, что искать, а не просто сказать ответ), я понимаю, что необходимо заранее обсудить:
SELECT DISTINCT
`Q`.`QID`
FROM
`S`
NATURAL JOIN `Q`
NATURAL JOIN `V`
NATURAL JOIN `R` AS `R1`
NATURAL JOIN `W`
JOIN `R` AS `R2` ON (
`R2`.`SID` = `S`.`SID`
AND `R2`.`RID` = `R1`.`RID`
AND `R2`.`VID` = `S`.`V_id`
AND `R2`.`Col_1_to_3` IN (1,2) -- this is where performance suffers!
)
WHERE
AND `S`.`SID` = @x
AND `W`.`WID` = @y
;
Определение таблицы R
:
CREATE TABLE `R` (
`SID` smallint(6) unsigned NOT NULL,
`RID` smallint(6) unsigned NOT NULL,
`VID` varchar(50) NOT NULL DEFAULT '',
`Col_1_to_3` smallint(1) DEFAULT NULL,
`T` varchar(255) DEFAULT NULL,
PRIMARY KEY (`SID`,`RID`,`VID`),
KEY `L` (`SID`,`VID`,`Col_1_to_3`),
CONSTRAINT `R_f1` FOREIGN KEY (`SID`) REFERENCES `S` (`SID`),
CONSTRAINT `R_f2` FOREIGN KEY (`SID`, `VID`) REFERENCES `V` (`SID`, `VID`),
CONSTRAINT `R_f3` FOREIGN KEY (`SID`, `VID`, `Col_1_to_3`) REFERENCES `L` (`SID`, `VID`, `LID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8