我对SQL有一定的经验,但是我仍然找不到如何高效执行以下查询性能的方法。
我有2个表-Box
和Item
。 Box
具有id
属性,该属性是主键(还有更多),而Item
具有box_id
,type
,name
。每个表都有数十亿条记录,每个盒子平均有10个项目。
我要查询所有具有至少一个具有给定类型的项以及至少一个具有给定名称(可以是相同或不同的项)的框。该查询应使用以下命令进行分页页面大小为10。
我在所有Item
属性上使用了单列索引。以下查询(第一页)需要很长时间(超过一分钟):
SELECT Box.id FROM Box WHERE
(EXISTS (SELECT 1 FROM Item WHERE Item.box_id = Box.id AND Item.type = 'my_type')) AND
(EXISTS (SELECT 1 FROM Item WHERE Item.box_id = Box.id AND Item.name = 'my_name'))
LIMIT 10
我认为问题在于在查询的每个部分中过滤出的框之间的交集(仅使用约束条件之一进行查询会返回大约一百万条记录)。我正在使用Aurora PostgreSQL 9.6.6。
答案 0 :(得分:2)
您尚未对这些澄清做出回应,因此我将假设一些事情:
Item.name = 'my_name'
Item
表的所有列都具有单列索引。id
是主键,因此它上面已经有一个索引。现在,我认为您正在使用的索引对于该查询而言并不是最佳选择,因为它们仅单独包含列。如果您还没有它们,请尝试创建以下索引:
create index ix1 on Item (box_id, type);
create index ix2 on Item (box_id, name);
是的,他们两个。再次尝试查询,看看需要多长时间。
如果仍然很慢,请使用以下方法发布解释计划:
EXPLAIN ANALYZE
SELECT Box.id
FROM Box
WHERE
(EXISTS (SELECT 1 FROM Item WHERE Item.box_id = Box.id AND Item.type = 'my_type'))
AND
(EXISTS (SELECT 1 FROM Item WHERE Item.box_id = Box.id AND Item.name = 'my_name'))
答案 1 :(得分:1)
INTERSECT
是另一种选择。
SELECT Box_id FROM Item
WHERE Item.type = 'my_type'
INTERSECT
SELECT Box_id FROM Item
WHERE Item.name = 'my_name'
注意:INTERSECT返回不同的值,因此不需要外部查询即可获得满足您条件的不同Box_id值的列表。该查询的确会返回孤立项目(box表中没有box_id的项目),因此在这种情况下可能需要外部查询。
答案 2 :(得分:0)
像这样吗?
SELECT DISTINCT ON (Box.id) Box.*
FROM Box
JOIN Item I1 ON I1.box_id = Box.id AND I1.type = 'my_type'
JOIN Item I2 ON I2.box_id = Box.id AND I2.name = 'my_name'
ORDER BY Box.id;
JOIN
会根据项目的类型和名称来过滤结果。