CCM*_*CCM 2 sql postgresql postgresql-performance
这个问题有一段时间了,想知道是否有更快的查询。
我有一个表,每个 ID 包含多个条目,并且想要列出同一 ID 具有不同值的所有列。
| ID | 品牌 | 类型 |
|---|---|---|
| 1 | 本田 | 轿跑车 |
| 1 | 吉普车 | SUV |
| 2 | 福特 | 轿车 |
| 2 | 福特 | 交叉 |
上表示例:
行ID = 1具有不同的Brand和Type值,因此我希望每一列有一个结果行。
由于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)
有没有更快的查询或优化?
您的查询适用于每个 ID 的几行(除了应该在的位置UNIONUNION 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有很多行(并且每个测试列上都有一个索引),则有(更多)更快的选项。如果是这样,并且很重要,请开始一个新问题,按照标签说明中的说明
提供postgresql 性能问题的信息。Postgres 版本、精确的表定义、测试用例。最重要的是,有关数据分布的粗略统计数据。并在此处发表评论以链接到后续内容。