优化每个 ID 具有不同值的列的查询

CCM*_*CCM 2 sql postgresql postgresql-performance

这个问题有一段时间了,想知道是否有更快的查询。

我有一个表,每个 ID 包含多个条目,并且想要列出同一 ID 具有不同值的所有列。

ID 品牌 类型
1 本田 轿跑车
1 吉普车 SUV
2 福特 轿车
2 福特 交叉

上表示例:
ID = 1具有不同的BrandType值,因此我希望每一列有一个结果行。
由于ID = 2只有一个品牌,但有多种类型,所以类型只有一个结果行。

想要的结果会是这样的。

ID 不同之处
1 品牌
1 类型
2 类型

我通过下面的查询解决了这个问题,用一个SELECT语句检查每一列,然后UNION全部完成:

SELECT ID, 'Brand' AS Discrepancy
FROM table
GROUP BY ID
HAVING COUNT(DISTINCT Brand) > 1

UNION 

SELECT ID,'Type' AS Discrepancy
FROM table
GROUP BY ID
HAVING COUNT(DISTINCT Type) > 1;
Run Code Online (Sandbox Code Playgroud)

有没有更快的查询或优化?

Erw*_*ter 5

您的查询适用于每个 ID 的行(除了UNION应该在的位置UNION ALL)。
这个更好:

SELECT t.id, c.difference
FROM  (
   SELECT id
        , count(DISTINCT brand) AS brand_ct
        , count(DISTINCT type)  AS type_ct
   FROM   tbl
   GROUP  BY id
   ) t
JOIN   LATERAL (
   VALUES
     ('Brand', t.brand_ct)
   , ('Type' , t.type_ct)
   ) c(difference, count) ON c.count > 1
ORDER  BY 1, 2;  -- optional
Run Code Online (Sandbox Code Playgroud)

或者甚至(正如Charlieface所暗示的):

SELECT t.id, c.difference
FROM  (
   SELECT id
        , min(brand) <> max(brand) AS b_diff
        , min(type)  <> max(type)  AS t_diff
   FROM   tbl
   GROUP  BY id
   ) t
JOIN   LATERAL (
   VALUES
     ('Brand', t.b_diff)
   , ('Type' , t.t_diff)
   ) c(difference, diff) ON c.diff
ORDER  BY 1, 2;  -- optional
Run Code Online (Sandbox Code Playgroud)

小提琴

一次顺序扫描可以使成本降低近一半。测试用EXPLAIN ANALYZE. 看:

请注意,任一查询都会忽略空值。

如果每个 ID有很多行(并且每个测试列上都有一个索引),则有(更多)更快的选项。如果是这样,并且很重要,请开始一个新问题,按照标签说明中的说明
提供问题的信息。Postgres 版本、精确的表定义、测试用例。最重要的是,有关数据分布的粗略统计数据。并在此处发表评论以链接到后续内容。

  • `MIN(x) &lt;&gt; MAX(x)` 可能比执行多个 `COUNT(DISTINCT` ) 快得多 (2认同)