带有order和limit子句的慢查询,但仅限于没有记录

时间:2016-02-06 04:24:44

标签: postgresql postgresql-9.4

我正在运行以下查询:

SELECT * FROM foo WHERE name = 'Bob' ORDER BY address DESC LIMIT 25 OFFSET 1

因为我在表中有name ='Bob'的记录,所以在10M记录(<.5秒)的表上查询时间很快

但是,如果我搜索name ='Susan',则查询需要45秒。我在表中没有记录name ='Susan'。

我对每个姓名和地址都有一个索引。我已经对表进行了清理,对其进行了分析,甚至尝试重新编写查询:

SELECT * FROM (SELECT * FROM foo WHERE name = 'Bob' ORDER BY address DESC) f LIMIT 25 OFFSET 1

并且找不到任何解决方案。我不确定如何继续。请注意,这与this post不同,因为我的缓慢只在没有记录时才会发生。

编辑: 如果我取出ORDER BY地址,那么它会很快运行。显然,我需要那里。我试过重写它(没有成功):

SELECT * FROM (SELECT * FROM foo WHERE name = 'Bob') f ORDER BY address DESC LIMIT 25 OFFSET 1

2 个答案:

答案 0 :(得分:1)

检查execution plan以查看正在使用的索引。在这种情况下,名称和地址的单独索引是不够的。您应该创建名称的组合索引,然后为此查询创建地址。

将索引视为系统维护的某些列的副本,其顺序与原始列不同。在这种情况下,您希望首先按名称查找匹配项,然后在地址上查找并入,然后再进行,直到您有足够的名称或用完名称匹配。

通过在多列索引中首先创建名称,索引将首先按名称排序。然后地址将成为我们的平局。

在原始索引下,如果地址索引是选择的地址索引,那么查询的速度将根据找到匹配的速度而有所不同。

计划(英文)将是:继续执行已经按地址排序的所有行,丢弃任何与名称不匹配的行,继续运行直到我们有足够的。

所以,如果你没有得到25场比赛,你就读完了整个桌子!

根据我提出的多列索引,计划(英文)将是:继续执行已经按地址排序的所有名称匹配行。从第一个开始,拿走它们,直到你有足够的。如果你用完了,请停止。

答案 1 :(得分:0)

由于情况是没有Order By的查询比具有Order By子句的查询快得多;我会提出两个问题:

- 没有订单,限制1,知道您是否至少有一条记录。

如果您至少有一个,则使用Order by运行查询是安全的。

- 如果没有记录,则无需运行第二个查询。

是的,这不是解决方案,但它可以让您交付项目。确保您在交付后创建一张处理技术债务的票据;)否则您的首席开发人员会让您着火。

然后,要解决真正的技术问题,了解您创建的索引将非常有用。没有这些,就很难给你一个合适的解决方案!

相关问题