【问题标题】:Solution for speeding up a slow SELECT DISTINCT query in Postgres在 Postgres 中加快慢速 SELECT DISTINCT 查询的解决方案
【发布时间】:2011-09-29 17:42:56
【问题描述】:

查询基本上是:

SELECT DISTINCT "my_table"."foo" from "my_table" WHERE...

假装我 100% 确定查询的 DISTINCT 部分是它运行缓慢的原因,我省略了查询的其余部分以避免混淆,因为我是不同部分的缓慢主要关注(distinct 总是缓慢的来源)。

有问题的表有 250 万行数据。 DISTINCT 需要用于此处未列出的目的(因为我不想返回修改后的查询,而只是关于使不同查询在 DBMS上运行得更快的一般信息> 级别,如果可能)。

如何在不更改 SQL 的情况下使DISTINCT 运行得更快(特别是使用 Postgres 9)(即,我无法更改传入的 SQL,但可以在数据库级别优化某些内容)?

【问题讨论】:

  • 需要完整的查询才能给出答案。通常,人们出于不好的原因使用 distinct。
  • @orokusaki :查询是一回事。它不是一侧的 distinct,另一侧的 join 和第三侧的 group by。这并不是因为您的查询在没有不同的情况下会更快,因此问题是不同的......您无法回答这样的问题。或者是的,你可以:使用索引。
  • @orokusaki:这真的取决于。通常,在查询中使用 distinct 反映了某处的次优连接。并非总是如此,但足够频繁。在这种情况下,想法是重写查询,以便子语句位于返回唯一行的子查询中(或使用 in() 子句进行检查)。
  • @Denis- 在性能方面存在次优连接,但无法避免。我正在过滤 M2M 关系(获取所有在其foos (m2m) 列表中具有 [x、y 或 z] 的用户。
  • 我不知道为什么人们很难让你假设不同的是慢速部分。将查询速度降低到这样的程度相对容易。

标签: sql database postgresql database-optimization


【解决方案1】:

通常,您可以通过使用group by 来解决distinct 来加快此类查询的运行速度:

select my_table.foo 
from my_table 
where [whatever where conditions you want]
group by foo;

【讨论】:

  • 我无法修改 SQL,这就是为什么我忽略了大部分查询。
  • 好吧,要么让用户(要么是编写运行这些查询的应用程序的开发人员,要么是临时运行这些查询的用户)切换他们的 SQL。如果你不能这样做,那么你可以通过在foo 上索引my_table 获得一些里程。
  • 这对我来说是一个很好的解决方案。我最初认为是大偏移量使我的查询运行缓慢,但在从 DISTINCT 切换到 GROUP BY 后,它们的运行速度提高了 20 倍。谢谢!
  • 感谢杰克的精彩提示!将 SELECT DISTINCT 替换为 GROUP BY 将我的特定查询的运行时间从 649 毫秒减少到 87 毫秒,几乎快了 7.5 倍。我的 INNER JOIN 位于一个包含 ~30,000 行的表(我想要从中匹配行)和另一个包含 ~322,000 行的连接表(我用来过滤第一行)之间。我已经为我的 INNER JOIN 和单个 WHERE 子句两侧使用的所有列添加了索引,所以我希望找到另一个有助于加快查询速度的优化,这在这种特殊情况下效果很好。跨度>
  • 问题是... 为什么这会使查询更快?
【解决方案2】:

您的 DISTINCT 导致它对输出行进行排序以查找重复项。如果您在查询选择的列上放置索引,数据库可能能够按索引顺序读取它们并保存排序步骤。很大程度上取决于查询的详细信息和所涉及的表——您说“知道问题出在 DISTINCT”确实限制了可用答案的范围。

【讨论】:

  • 我知道它限制了答案的范围,这就是我这样做的原因。我只寻找在数据库级别发生的答案,这就是你给我的 (+1)。
  • 仅有索引是不够的。我的不同列上有一个索引,但查询仍然需要几分钟才能搜索 800 万行以找到 4 个不同的值。
  • 请参阅 stackoverflow.com/a/14732410/32453 将 select distinct 查询放在子查询中并计算这对我有用,奇怪的是。
【解决方案3】:

您可以尝试增加 work_mem 设置,具体取决于您的数据集的大小。这可能会导致将查询计划切换到散列聚合,这通常更快。

但在全局设置太高之前,请先阅读它。您可以轻松炸毁您的服务器,因为max_connections 设置充当此数字的乘数。

这意味着如果您要设置work_mem = 128MB 并设置max_connections = 100(默认值),您应该有超过 12.8GB 的​​ RAM。您实际上是在告诉服务器它可以使用那么多来执行查询(甚至不考虑 Postgres 或其他方式使用的任何其他内存)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-11-22
    • 2014-09-21
    • 2021-07-06
    • 2013-05-08
    • 2011-07-03
    • 2018-06-25
    • 2016-01-10
    相关资源
    最近更新 更多