具有多个过滤器的一对多关系的SQL查询

时间:2018-10-10 17:00:24

标签: sql postgresql join one-to-many

我对SQL有一定的经验,但是我仍然找不到如何高效执行以下查询性能的方法。

我有2个表-BoxItemBox具有id属性,该属性是主键(还有更多),而Item具有box_idtypename。每个表都有数十亿条记录,每个盒子平均有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。

3 个答案:

答案 0 :(得分:2)

您尚未对这些澄清做出回应,因此我将假设一些事情:

  • 您想要所有的盒子,而不仅仅是10个。
  • 按名称比较时有错字。应该是:Item.name = 'my_name'
  • 您说“我已索引所有Item属性。”我假设您对Item表的所有列都具有单列索引。
  • Box的列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会根据项目的类型和名称来过滤结果。