MySQL 具有多个连接的查询
MySQL query with many joins
我有很多联接的查询,我正在为其搜索优化。
关于电脑:
例如我有:
Lenovo 8gbRAM 1TB core i5 ips 等(品牌名称后均为属性)
我有配置,我想将属性 8gbRAM 更改为 16gbRAM,我必须搜索具有所有这些属性和 16gbRAM
的其他项目
两个表:
**st_item**
- id
- name
...
**st_item_specification_attribute**
- id
- st_item_id
- attribute_id
- attribute_value_id
...
我的问题是我的商品有 15 个属性。当我使用较少数量的属性进行测试时,我使用了这种查询结构并且它有效,但现在系统有 85k 个项目和超过 1kk 个项目属性
这是查询:
SELECT `st_item`.id FROM `st_item`
LEFT JOIN `st_item_specification_attribute` `sisa_36590` ON st_item.id = sisa_36590.item_id AND sisa_36590.attribute_id = 365
LEFT JOIN `st_item_specification_attribute` `sisa_367910` ON st_item.id = sisa_367910.item_id AND sisa_367910.attribute_id = 367
LEFT JOIN `st_item_specification_attribute` `sisa_374641` ON st_item.id = sisa_374641.item_id AND sisa_374641.attribute_id = 374
LEFT JOIN `st_item_specification_attribute` `sisa_378366` ON st_item.id = sisa_378366.item_id AND sisa_378366.attribute_id = 378
LEFT JOIN `st_item_specification_attribute` `sisa_382500` ON st_item.id = sisa_382500.item_id AND sisa_382500.attribute_id = 382
LEFT JOIN `st_item_specification_attribute` `sisa_372134` ON st_item.id = sisa_372134.item_id AND sisa_372134.attribute_id = 372
LEFT JOIN `st_item_specification_attribute` `sisa_41268` ON st_item.id = sisa_41268.item_id AND sisa_41268.attribute_id = 412
LEFT JOIN `st_item_specification_attribute` `sisa_413368` ON st_item.id = sisa_413368.item_id AND sisa_413368.attribute_id = 413
LEFT JOIN `st_item_specification_attribute` `sisa_414929` ON st_item.id = sisa_414929.item_id AND sisa_414929.attribute_id = 414
LEFT JOIN `st_item_specification_attribute` `sisa_418496` ON st_item.id = sisa_418496.item_id AND sisa_418496.attribute_id = 418
LEFT JOIN `st_item_specification_attribute` `sisa_385748` ON st_item.id = sisa_385748.item_id AND sisa_385748.attribute_id = 385
LEFT JOIN `st_item_specification_attribute` `sisa_36625` ON st_item.id = sisa_36625.item_id AND sisa_36625.attribute_id = 366
LEFT JOIN `st_item_specification_attribute` `sisa_366355` ON st_item.id = sisa_366355.item_id AND sisa_366355.attribute_id = 366
LEFT JOIN `st_item_specification_attribute` `sisa_366816` ON st_item.id = sisa_366816.item_id AND sisa_366816.attribute_id = 366
LEFT JOIN `st_item_specification_attribute` `sisa_366370` ON st_item.id = sisa_366370.item_id AND sisa_366370.attribute_id = 366
WHERE (`parent_id`=1032) AND
(sisa_36590.attribute_value_id = 2230) AND
(sisa_367910.attribute_value_id = 2451) AND
(sisa_374641.attribute_value_id = 3793) AND
(sisa_378366.attribute_value_id = 2955) AND
(sisa_382500.attribute_value_id = 3879) AND
(sisa_372134.attribute_value_id = 2780) AND
(sisa_41268.attribute_value_id = 3363) AND
(sisa_413368.attribute_value_id = 3373) AND
(sisa_414929.attribute_value_id = 3378) AND
(sisa_418496.attribute_value_id = 3844) AND
(sisa_385748.attribute_value_id = 3036) AND
(sisa_36625.attribute_value_id = 2315) AND
(sisa_366355.attribute_value_id = 2408) AND
(sisa_366816.attribute_value_id = 2412) AND
(sisa_366370.attribute_value_id = 2420)
查询必须比较特定的对 attribute_id => attribute_value_id
,这就是我的“ON 子句”与 item_id
和 attribute_id
以及特定的 alias
的原因
您可以将您的 WHERE
条件移动到 ON
条件
并将 LEFT JOIN
更改为 INNER JOIN
.
SELECT `st_item`.id FROM `st_item`
JOIN `st_item_specification_attribute` `sisa_36590`
ON st_item.id = sisa_36590.item_id AND sisa_36590.attribute_id = 365
AND sisa_36590.attribute_value_id = 2230
JOIN `st_item_specification_attribute` `sisa_367910`
ON st_item.id = sisa_367910.item_id AND sisa_367910.attribute_id = 367
AND sisa_367910.attribute_value_id = 2451
...
WHERE `parent_id`=1032
第二种方法
SELECT `st_item`.id FROM `st_item`
JOIN `st_item_specification_attribute` `sisa`
ON st_item.id = sisa.item_id AND
(
(sisa.attribute_id = 365 AND sisa.attribute_value_id = 2230)
OR
(sisa.attribute_id = 367 AND sisa.attribute_value_id = 2451)
...
)
WHERE `parent_id`=1032
GROUP BY `st_item`.id
HAVING COUNT(*) = 15
您可以使用聚合:
select i.id
from st_item i join
st_item_specification_attribute sisa
ON sisa.item_id = i.item_id
where i.parent_id = 1032 and
(sisa.attribute_id, attribute_value_id) in ( (365, 2230), (367, 2451), . . .)
group by i.id
having count(*) = 15;
我无法预测性能,但我认为您可以从所有联接中进行子选择
(我假设 atribute_id 和 Attribute_value_id 对在 item_id 中是唯一的)
SELECT `st_item`.id FROM `st_item`
WHERE (`parent_id`=1032) AND
15 = (SELECT COUNT(*) FROM st_item_specification_attribute attr
WHERE `st_item`.id = attr.item_id
AND ( attribute_id = 365 AND attribute_value_id = 2230 OR
...
)
我会为此使用 UNION ALL 方法。它很容易改变,而且相当容易阅读。性能应该也不错:
--A CTE so you only have to change parent_id in one place
--I believe not all mysql versions support this, though
--You could of course just select the parent_id in de UNION ALL and
-- use a single WHERE in the outer query.
WITH st_item_id AS
(
SELECT id
, attribute_id
, attribute_value_id
FROM st_item
WHERE parent_id = 1032
)
SELECT UA.id
FROM (
SELECT st_item.id
FROM st_item_id
INNER JOIN st_item_specification_attribute sisa_36590
ON st_item_id.id = sisa_36590.item_id
AND sisa_36590.attribute_id = 365
AND sisa_36590.attribute_value_id = 2230
UNION ALL
SELECT st_item.id
FROM st_item_id
INNER JOIN st_item_specification_attribute sisa_367910
ON st_item_id.id = sisa_367910.item_id
AND sisa_367910.attribute_id = 367
AND sisa_367910.attribute_value_id = 2451
) UA
我有很多联接的查询,我正在为其搜索优化。 关于电脑: 例如我有: Lenovo 8gbRAM 1TB core i5 ips 等(品牌名称后均为属性) 我有配置,我想将属性 8gbRAM 更改为 16gbRAM,我必须搜索具有所有这些属性和 16gbRAM
的其他项目两个表:
**st_item**
- id
- name
...
**st_item_specification_attribute**
- id
- st_item_id
- attribute_id
- attribute_value_id
...
我的问题是我的商品有 15 个属性。当我使用较少数量的属性进行测试时,我使用了这种查询结构并且它有效,但现在系统有 85k 个项目和超过 1kk 个项目属性 这是查询:
SELECT `st_item`.id FROM `st_item`
LEFT JOIN `st_item_specification_attribute` `sisa_36590` ON st_item.id = sisa_36590.item_id AND sisa_36590.attribute_id = 365
LEFT JOIN `st_item_specification_attribute` `sisa_367910` ON st_item.id = sisa_367910.item_id AND sisa_367910.attribute_id = 367
LEFT JOIN `st_item_specification_attribute` `sisa_374641` ON st_item.id = sisa_374641.item_id AND sisa_374641.attribute_id = 374
LEFT JOIN `st_item_specification_attribute` `sisa_378366` ON st_item.id = sisa_378366.item_id AND sisa_378366.attribute_id = 378
LEFT JOIN `st_item_specification_attribute` `sisa_382500` ON st_item.id = sisa_382500.item_id AND sisa_382500.attribute_id = 382
LEFT JOIN `st_item_specification_attribute` `sisa_372134` ON st_item.id = sisa_372134.item_id AND sisa_372134.attribute_id = 372
LEFT JOIN `st_item_specification_attribute` `sisa_41268` ON st_item.id = sisa_41268.item_id AND sisa_41268.attribute_id = 412
LEFT JOIN `st_item_specification_attribute` `sisa_413368` ON st_item.id = sisa_413368.item_id AND sisa_413368.attribute_id = 413
LEFT JOIN `st_item_specification_attribute` `sisa_414929` ON st_item.id = sisa_414929.item_id AND sisa_414929.attribute_id = 414
LEFT JOIN `st_item_specification_attribute` `sisa_418496` ON st_item.id = sisa_418496.item_id AND sisa_418496.attribute_id = 418
LEFT JOIN `st_item_specification_attribute` `sisa_385748` ON st_item.id = sisa_385748.item_id AND sisa_385748.attribute_id = 385
LEFT JOIN `st_item_specification_attribute` `sisa_36625` ON st_item.id = sisa_36625.item_id AND sisa_36625.attribute_id = 366
LEFT JOIN `st_item_specification_attribute` `sisa_366355` ON st_item.id = sisa_366355.item_id AND sisa_366355.attribute_id = 366
LEFT JOIN `st_item_specification_attribute` `sisa_366816` ON st_item.id = sisa_366816.item_id AND sisa_366816.attribute_id = 366
LEFT JOIN `st_item_specification_attribute` `sisa_366370` ON st_item.id = sisa_366370.item_id AND sisa_366370.attribute_id = 366
WHERE (`parent_id`=1032) AND
(sisa_36590.attribute_value_id = 2230) AND
(sisa_367910.attribute_value_id = 2451) AND
(sisa_374641.attribute_value_id = 3793) AND
(sisa_378366.attribute_value_id = 2955) AND
(sisa_382500.attribute_value_id = 3879) AND
(sisa_372134.attribute_value_id = 2780) AND
(sisa_41268.attribute_value_id = 3363) AND
(sisa_413368.attribute_value_id = 3373) AND
(sisa_414929.attribute_value_id = 3378) AND
(sisa_418496.attribute_value_id = 3844) AND
(sisa_385748.attribute_value_id = 3036) AND
(sisa_36625.attribute_value_id = 2315) AND
(sisa_366355.attribute_value_id = 2408) AND
(sisa_366816.attribute_value_id = 2412) AND
(sisa_366370.attribute_value_id = 2420)
查询必须比较特定的对 attribute_id => attribute_value_id
,这就是我的“ON 子句”与 item_id
和 attribute_id
以及特定的 alias
您可以将您的 WHERE
条件移动到 ON
条件
并将 LEFT JOIN
更改为 INNER JOIN
.
SELECT `st_item`.id FROM `st_item`
JOIN `st_item_specification_attribute` `sisa_36590`
ON st_item.id = sisa_36590.item_id AND sisa_36590.attribute_id = 365
AND sisa_36590.attribute_value_id = 2230
JOIN `st_item_specification_attribute` `sisa_367910`
ON st_item.id = sisa_367910.item_id AND sisa_367910.attribute_id = 367
AND sisa_367910.attribute_value_id = 2451
...
WHERE `parent_id`=1032
第二种方法
SELECT `st_item`.id FROM `st_item`
JOIN `st_item_specification_attribute` `sisa`
ON st_item.id = sisa.item_id AND
(
(sisa.attribute_id = 365 AND sisa.attribute_value_id = 2230)
OR
(sisa.attribute_id = 367 AND sisa.attribute_value_id = 2451)
...
)
WHERE `parent_id`=1032
GROUP BY `st_item`.id
HAVING COUNT(*) = 15
您可以使用聚合:
select i.id
from st_item i join
st_item_specification_attribute sisa
ON sisa.item_id = i.item_id
where i.parent_id = 1032 and
(sisa.attribute_id, attribute_value_id) in ( (365, 2230), (367, 2451), . . .)
group by i.id
having count(*) = 15;
我无法预测性能,但我认为您可以从所有联接中进行子选择
(我假设 atribute_id 和 Attribute_value_id 对在 item_id 中是唯一的)
SELECT `st_item`.id FROM `st_item`
WHERE (`parent_id`=1032) AND
15 = (SELECT COUNT(*) FROM st_item_specification_attribute attr
WHERE `st_item`.id = attr.item_id
AND ( attribute_id = 365 AND attribute_value_id = 2230 OR
...
)
我会为此使用 UNION ALL 方法。它很容易改变,而且相当容易阅读。性能应该也不错:
--A CTE so you only have to change parent_id in one place
--I believe not all mysql versions support this, though
--You could of course just select the parent_id in de UNION ALL and
-- use a single WHERE in the outer query.
WITH st_item_id AS
(
SELECT id
, attribute_id
, attribute_value_id
FROM st_item
WHERE parent_id = 1032
)
SELECT UA.id
FROM (
SELECT st_item.id
FROM st_item_id
INNER JOIN st_item_specification_attribute sisa_36590
ON st_item_id.id = sisa_36590.item_id
AND sisa_36590.attribute_id = 365
AND sisa_36590.attribute_value_id = 2230
UNION ALL
SELECT st_item.id
FROM st_item_id
INNER JOIN st_item_specification_attribute sisa_367910
ON st_item_id.id = sisa_367910.item_id
AND sisa_367910.attribute_id = 367
AND sisa_367910.attribute_value_id = 2451
) UA