这需要大约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
?
P.S。 MySQL版本:5.6.33
正如O.Jones指出的那样,我尝试FORCE INDEX (PRIMARY)
使用表category_1
并且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 秒。
虽然这回答了这个特定查询的问题,但它显然是 NOT 最终解决方案,因为人们可能还需要通过两者来搜索汽车零件 { {1}}和category_1
,因此无法删除查询中的任何JOIN:
make
经过多次测试后,仍然会持续约 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`)
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
必须使用JOIN而不是LEFT JOIN,否则条件不会生效。
然而,当条件在WHERE子句中时,它仍然像SLOW一样慢。
答案 0 :(得分:0)
很少有建议尝试加快查询速度(我查看了上次更新,#3):
category_1.id > 0
)。因此,您可以将LEFT一词移除到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`);