PostgreSQL多个'WHERE'条件(1000+)请求

时间:2016-07-10 06:24:09

标签: java database postgresql performance spring-mvc

我根本不是SQL的专业人士:) 有一个非常关键的性能问题。 以下是与问题直接相关的信息。

我的数据库表condos和表goods中有2个表。

condos包含字段:

  • id(PK)
  • 名称
  • 城市
  • 国家

表项目:

  • id(PK)
  • 名称
  • 与问题无关的多个字段
  • condo_id(FK)

我在condos表中有1000多个实体,在items表中有1000多个实体。

问题是我如何执行项目搜索

目前是:

例如,我想获取city = Sydney

的所有项目
  1. 执行SELECT condos.condo_id FROM public.condos WHERE city = 'Sydney'
  2. 为步骤1中的每个SELECT * FROM public.items WHERE item.condo_id = ?制作一个condo_id
  3. 问题是,一旦我在condos表中获得了1000多个实体,则每个condo_id属于“悉尼”的请求执行1000次以上。并且执行此请求需要花费大约2分钟,这是一个关键的性能问题。

    所以,问题是:

    我执行此类搜索的最佳方式是什么?我应该在单WHERE个请求中添加1000+ id吗?或?

    对于添加信息,我使用 PostgreSQL 9.4 Spring MVC

3 个答案:

答案 0 :(得分:2)

使用表join执行查询,这样您就不需要执行其他查询。在您的情况下,您可以通过condos加入itemscondo_id,例如:

SELECT i.* 
FROM public.items i join public.condos c on i.condo_id = c.condo_id 
WHERE c.city = 'Sydney'  

请注意,性能调优是一个主题。它可以因环境而异,取决于您如何构建表中的数据以及如何组织代码中的数据。

以下是其他一些可能也有帮助的建议:

尝试将索引添加到您使用排序和搜索的字段,例如city中的condoscondo_id中的items。有一个很好的answer来解释索引的工作原理。

我还建议您执行EXPLAIN为您的查询设计查询计划是否存在可能导致性能问题的全表搜索。

希望这可以提供帮助。

答案 1 :(得分:1)

基本上你需要的是消除N + 1查询,同时确保你的城市字段被编入索引。你有3种机制可以去。在您收到的其他一个答案中已经说明了一个是SUBSELECT方法。除了这种方法,你还有两个。

您可以使用您所声明的内容:

SELECT condos.condo_id FROM public.condos WHERE city = 'Sydney'

SELECT * 
FROM   public.items 
WHERE  items.condo_id IN (up to 1000 ids here) 

我之前提到1000的原因是因为某些SQL提供商有限制。

您也可以通过联接来消除N + 1选择

SELECT * 
FROM   public.items join  public.condos on items.condo_id=condos.condo_id  and condos.city='Sydney'

现在3个查询之间有什么区别。

Subselect查询的优点是您一次获得所有内容。 缺点是,如果你有太多的元素,性能可能会受到影响:

简单的优点条款。有效地解决了N + 1问题, 与Subselect

相比,缺点可能导致一些额外的查询

加入查询专家,您可以一次性初始化公寓和项目。 缺点导致公寓方面的一些数据重复

如果我们看一下像Hibernate这样的框架,我们可以发现在大多数情况下,使用获取策略或者加入IN策略。很少使用子选择。

此外,如果您有关键性能,您可以考虑阅读内存中的所有内容并从那里提供服务。从这两个表的内容来看,将其上传到Map中应该相当容易。

如果我们只讨论1000次查询,那么解决您的N + 1查询问题的所有内容都是您的解决方案。所有这三个选项都是解决方案。

答案 2 :(得分:0)

您可以在第二个查询中将第一个查询用作in运算符中的子查询:

SELECT * 
FROM   public.items 
WHERE  item.condo_id IN (SELECT condos.condo_id 
                         FROM   public.condos
                         WHERE  city = 'Sydney')