[英]Why is this MySQL query incredibly slow and not using the right index?
執行大約需要100秒:
SELECT part.*
FROM (((((((`part`
LEFT JOIN `engine_x_category_1_x_category_2_x_part`
ON `engine_x_category_1_x_category_2_x_part`.`part_id` =
`part`.`id`)
LEFT JOIN `engine_x_category_1_x_category_2`
ON
`engine_x_category_1_x_category_2_x_part`.`engine_x_category_1_x_category_2_id`
= `engine_x_category_1_x_category_2`.`id`)
LEFT JOIN `engine_x_category_1`
ON `engine_x_category_1_x_category_2`.`engine_x_category_1_id` =
`engine_x_category_1`.`id`)
LEFT JOIN `engine`
ON `engine_x_category_1`.`engine_id` = `engine`.`id`)
LEFT JOIN `model`
ON `engine`.`model_id` = `model`.`id`)
LEFT JOIN `year`
ON `model`.`year_id` = `year`.`id`)
LEFT JOIN `make`
ON `year`.`make_id` = `make`.`id`)
LEFT JOIN `category_1`
ON `engine_x_category_1`.`category_1_id` = `category_1`.`id`
WHERE 1 > 0
AND `category_1`.`id` > 0
GROUP BY `part`.`id`
ORDER BY `part`.`id` ASC
LIMIT 0, 20
但是,一旦我們擺脫AND category_1.id > 0
,它只需要0.003秒。
這真的很奇怪,因為category_1.id
是PRIMARY KEY列,而表category_1
只有26行。
category_1
結構和鍵 這有什么問題嗎? 為什么MySQL不為category_1.id
使用PRIMARY索引,而是為時間戳列使用索引ts
?
PS MySQL版本:5.6.33
正如O. Jones指出的那樣,我嘗試使用表category_1
FORCE INDEX (PRIMARY)
,並且EXPLAIN顯示查詢正確使用了PRIMARY而不是ts作為category_1.id
的索引,但是查詢仍然需要近100秒鍾來執行。
似乎category_1.id
不是這里的罪魁禍首。
在@ O.Jones的建議之后,我擺脫了與make
, year
, model
和engine
無關的JOIN:
SELECT part.*
FROM (((`part`
LEFT JOIN `engine_x_category_1_x_category_2_x_part`
ON `engine_x_category_1_x_category_2_x_part`.`part_id` =
`part`.`id`)
LEFT JOIN `engine_x_category_1_x_category_2`
ON
`engine_x_category_1_x_category_2_x_part`.`engine_x_category_1_x_category_2_id`
= `engine_x_category_1_x_category_2`.`id`)
LEFT JOIN `engine_x_category_1`
ON `engine_x_category_1_x_category_2`.`engine_x_category_1_id` =
`engine_x_category_1`.`id`)
LEFT JOIN `category_1`
ON `engine_x_category_1`.`category_1_id` = `category_1`.`id`
WHERE 1 > 0
AND `category_1`.`id` > 0
GROUP BY `part`.`id`
ORDER BY `part`.`id` ASC
LIMIT 0, 20
現在查詢僅花費大約0.003秒。
雖然這可以回答此特定查詢的問題,但它顯然不是最終的解決方案,因為人們可能還需要同時通過category_1
和make
來搜索汽車零件,因此無法刪除查詢中的任何JOIN:
SELECT part.*
FROM (((((((`part`
LEFT JOIN `engine_x_category_1_x_category_2_x_part`
ON `engine_x_category_1_x_category_2_x_part`.`part_id` =
`part`.`id`)
LEFT JOIN `engine_x_category_1_x_category_2`
ON
`engine_x_category_1_x_category_2_x_part`.`engine_x_category_1_x_category_2_id`
= `engine_x_category_1_x_category_2`.`id`)
LEFT JOIN `engine_x_category_1`
ON `engine_x_category_1_x_category_2`.`engine_x_category_1_id` =
`engine_x_category_1`.`id`)
LEFT JOIN `engine`
ON `engine_x_category_1`.`engine_id` = `engine`.`id`)
LEFT JOIN `model`
ON `engine`.`model_id` = `model`.`id`)
LEFT JOIN `year`
ON `model`.`year_id` = `year`.`id`)
LEFT JOIN `make`
ON `year`.`make_id` = `make`.`id`)
LEFT JOIN `category_1`
ON `engine_x_category_1`.`category_1_id` = `category_1`.`id`
WHERE 1 > 0
AND `category_1`.`id` > 0
AND `make`.`id` > 0
GROUP BY `part`.`id`
ORDER BY `part`.`id` ASC
LIMIT 0, 20
經過幾次測試,它仍然可以運行約80-100秒。
我們現在該做什么?
遵循@LuisMuñoz的建議,我將條件從WHERE移到了相應的JOIN ON子句:
SELECT part.*
FROM (((((((`part`
LEFT JOIN `engine_x_category_1_x_category_2_x_part`
ON `engine_x_category_1_x_category_2_x_part`.`part_id` =
`part`.`id`)
LEFT JOIN `engine_x_category_1_x_category_2`
ON
`engine_x_category_1_x_category_2_x_part`.`engine_x_category_1_x_category_2_id`
= `engine_x_category_1_x_category_2`.`id`)
LEFT JOIN `engine_x_category_1`
ON `engine_x_category_1_x_category_2`.`engine_x_category_1_id` =
`engine_x_category_1`.`id`)
LEFT JOIN `engine`
ON `engine_x_category_1`.`engine_id` = `engine`.`id`)
LEFT JOIN `model`
ON `engine`.`model_id` = `model`.`id`)
LEFT JOIN `year`
ON `model`.`year_id` = `year`.`id`)
JOIN `make`
ON `year`.`make_id` = `make`.`id`
AND `make`.`id` > 0)
JOIN `category_1`
ON `engine_x_category_1`.`category_1_id` = `category_1`.`id`
AND `category_1`.`id` > 0
WHERE 1 > 0
GROUP BY `part`.`id`
LIMIT 0, 10
必須使用JOIN代替LEFT JOIN,否則條件將不生效。
但是,它仍然像條件在WHERE子句中一樣慢。
很少有建議嘗試加快查詢速度(我查看了最近的更新#3):
category_1.id > 0
)。 因此,您可以改為將單詞LEFT to INNER JOIN刪除到該表中,這可以加快查詢速度。 添加以下索引:
ALTER TABLE `category_1` ADD INDEX `category_1_idx_id` (`id`);
ALTER TABLE `engine_x_category_1` ADD INDEX `engine_x_category_1_idx_id` (`category_1_id`);
ALTER TABLE `make` ADD INDEX `make_idx_id` (`id`);
ALTER TABLE `part` ADD INDEX `part_idx_id` (`id`);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.