优化 COUNT(DISTINCT) SQL 查询

Posted

技术标签:

【中文标题】优化 COUNT(DISTINCT) SQL 查询【英文标题】:Optimizing COUNT(DISTINCT) SQL query 【发布时间】:2017-10-03 15:56:04 【问题描述】:

我有两张桌子A,B:

A 包含两列,与 B 相比,行数相对较少(千):

id, build_id (string)

B 包含三列并且有大量的行(数十万):

 id, build_id (string), task_id (string)

一个给定的构建可能有很多任务。我想获得一个表格,其中包含所有构建和每个构建的最新任务 ID 以及该构建的任务数。我的查询如下:

SELECT 
    A.build_id, 
    MAX(B.id) as latest_task_id, 
    COUNT(DISTINCT B.task_id) AS task_count 
FROM 
    A
LEFT OUTER JOIN 
    B ON B.build_id = A.build_id 
GROUP BY 
    A.build_id

有什么办法可以优化吗? build_id 和 task_id 上已经有索引了。

更新:这是在 postgres 9.6+ 上

【问题讨论】:

哪个 postgres 版本?这很重要,因为您可以在 9.6+ 上进行优化 mysql 和 postgresql 是两种不同的产品,具有不同的 sql 实现。你用哪一个?另外,为什么需要优化查询?慢吗?如果是,它有多慢?受影响的记录数量大致是多少? 用您真正使用的数据库标记您的问题。我删除了不兼容的数据库标签。 请edit您的问题并添加使用explain (analyze, verbose, format text)生成的执行计划。 Formatted text 请no screen shots B.task_id 在任一表中是否唯一? (如果是这样,创建唯一索引可能会有所帮助) 【参考方案1】:

尝试在join 之前进行聚合:

SELECT A.build_id, 
       MAX(B.id) as latest_task_id, 
       COUNT(B.task_id) AS task_count
FROM A LEFT OUTER JOIN
     (SELECT B.build_id, B.task_id, MAX(B.id) as id
      FROM B
      GROUP BY B.build_id, B.task_id
     ) B
     ON B.build_id = A.build_id
GROUP BY A.build_id;

有时,整体聚合的算法比COUNT(DISTINCT) 更有效。

您还可以为此查询尝试在B(build_id, task_id, id) 上建立索引。

【讨论】:

这个查询加快了速度,谢谢!。然而,覆盖指数并没有帮助。

以上是关于优化 COUNT(DISTINCT) SQL 查询的主要内容,如果未能解决你的问题,请参考以下文章

SQL优化 快速计算Distinct Count

Hive Count Distinct优化

非常慢的 MySQL COUNT DISTINCT 查询,即使有索引——如何优化?

Hive Count Distinct 优化

Hive Count Distinct 优化

sql优化