【问题标题】:PostgreSQL distinct rows joined with a count of distinct values in one columnPostgreSQL 不同的行与一列中的不同值的计数相连接
【发布时间】:2015-05-02 09:59:29
【问题描述】:

我使用的是 PostgreSQL 9.4,我有一个包含 1300 万行的表,数据大致如下:

  a  | b | u  | t 
-----+---+----+----
 foo | 1 |  1 | 10
 foo | 1 |  2 | 11
 foo | 1 |  2 | 11
 foo | 2 |  4 | 1
 foo | 3 |  5 | 2
 bar | 1 |  6 | 2
 bar | 2 |  7 | 2
 bar | 2 |  8 | 3
 bar | 3 |  9 | 4
 bar | 4 | 10 | 5
 bar | 5 | 11 | 6
 baz | 1 | 12 | 1
 baz | 1 | 13 | 2
 baz | 1 | 13 | 2
 baz | 1 | 13 | 3

md5(a)b(md5(a), b) 上有索引。 (实际上,a 可能包含超过 4k 个字符的值。)还有一个 SERIAL 类型的主键列,我在上面省略了。

我正在尝试构建一个将返回以下结果的查询:

  a  | b | u  | t  | z 
-----+---+----+----+---
 foo | 1 |  1 | 10 | 3
 foo | 1 |  2 | 11 | 3
 foo | 2 |  4 | 1  | 3
 foo | 3 |  5 | 2  | 3
 bar | 1 |  6 | 2  | 5
 bar | 2 |  7 | 2  | 5
 bar | 2 |  8 | 3  | 5
 bar | 3 |  9 | 4  | 5
 bar | 4 | 10 | 5  | 5
 bar | 5 | 11 | 6  | 5

在这些结果中,所有行都被删除重复数据,就像应用了 GROUP BY a, b, u, t 一样,zb 的每个分区的不同值的计数 a,并且只有 z 值更大的行超过 2 个。

我可以让z 过滤器按如下方式工作:

SELECT a, COUNT(b) AS z from (SELECT DISTINCT a, b FROM t) AS foo GROUP BY a
  HAVING COUNT(b) > 2;

但是,我很难将它与表中的其余数据结合起来。

最有效的方法是什么?

【问题讨论】:

    标签: sql postgresql count distinct aggregate-functions


    【解决方案1】:

    您的第一步已经可以更简单了:

    SELECT md5(a) AS md5_a, count(DISTINCT b) AS z
    FROM   t
    GROUP  BY 1
    HAVING count(DISTINCT b) > 2;
    

    使用md5(a) 代替a,因为a 显然可以非常 长,并且您已经在md5(a) 等上有一个索引。

    由于您的表很大,您需要一个高效的查询。这应该是最快的解决方案之一 - 具有足够的索引支持。您在(md5(a), b) 上的索引是有帮助的,但假设but 是小列-(md5(a), b, u, t) 上的索引对于查询的第二步(横向连接)会更好。

    您想要的最终结果:

    SELECT DISTINCT ON (md5(t.a), b, u, t)
           t.a, t.b, t.u, t.t, a.z
    FROM  (
       SELECT md5(a) AS md5_a, count(DISTINCT b) AS z
       FROM   t
       GROUP  BY 1
       HAVING count(DISTINCT b) > 2
       ) a
    JOIN   t ON md5(t.a) = md5_a
    ORDER  BY 1, 2, 3, 4;  -- optional
    

    或者可能更快,但是:

    SELECT a, b, u, t, z
    FROM  (
       SELECT DISTINCT ON (1, 2, 3, 4)
              md5(t.a) AS md5_a, t.b, t.u, t.t, t.a
       FROM   t
       ) t
    JOIN  (
       SELECT md5(a) AS md5_a, count(DISTINCT b) AS z
       FROM   t
       GROUP  BY 1
       HAVING count(DISTINCT b) > 2
       ) z USING (md5_a)
    ORDER  BY 1, 2, 3, 4;  -- optional
    

    DISTINCT ON详细解释:

    【讨论】:

    • 感谢您的帮助!
    • DISTINCT ON () 是否比 Lateral Join 有任何性能优势,反之亦然?
    • @AbhishekDalvi:两种截然不同的工具。 (我现在删除了因问题澄清而无效的答案部分。)在链接答案中对DISTINCT ON 性能的详细评估:stackoverflow.com/a/7630564/939860LATERAL 的详细信息:stackoverflow.com/a/28557803/939860
    猜你喜欢
    • 2011-09-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-11
    • 2021-12-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多