Sam*_*Sam 4 postgresql performance union
我的 Postgres 数据库中有一个表 (t0),其中的数据如下所示:
t1_id t2_id
1 1
2 1
2 1
4 null
4 null
5 null
Run Code Online (Sandbox Code Playgroud)
我有一个查询要返回我想要的结果:
t1_id t2_id
1 1
4 null
5 null
Run Code Online (Sandbox Code Playgroud)
我的查询看起来像这样:
(
SELECT DISTINCT ON (t2_id) t1_id, t2_id
FROM t0
WHERE t2_id IS NOT NULL
)
UNION ALL
(
SELECT DISTINCT ON (t1_id) t1_id, t2_id
FROM t0
WHERE t2_id IS NULL
)
Run Code Online (Sandbox Code Playgroud)
有没有更快的方法来执行这样的操作?这还不错,但是我在几个地方(使用连接)这样做,所有这些重复的查询似乎都会减慢速度。看来必须有更好的办法了。
这是小提琴形式的查询:http://sqlfiddle.com/#!15 /d41d8/3603
对于简单的情况,我只能想到对查询进行微小的改进:
(
SELECT DISTINCT ON (t2_id)
t1_id, t2_id
FROM t0
WHERE t2_id IS NOT NULL
ORDER BY t2_id, t1_id -- to get consistent results
)
UNION ALL
(
SELECT DISTINCT ON (t1_id)
t1_id, NULL -- cheaper
FROM t0
WHERE t2_id IS NULL
-- if you retrieve more columns, add ORDER BY, too
)
Run Code Online (Sandbox Code Playgroud)
正如ypercube 提到的,您需要添加ORDER BY
明确的表达式列表才能获得确定性结果。
您可以在查询的第二部分中使用常量NULL
而不是。t2_id
也与以下指数支撑相关。
性能的关键是索引。尝试使用两个部分索引来匹配查询的两个部分:
CREATE INDEX t0_part1_idx ON t0 (t2_id, t1_id) WHERE t2_id IS NOT NULL;
CREATE INDEX t0_part2_idx ON t0 (t1_id) WHERE t2_id IS NULL;
Run Code Online (Sandbox Code Playgroud)
您可能想也可能不想包含额外的列以允许仅索引扫描。
根据表大小和数据分布,可能有更快的替代方案:
SELECT
如果你想把它压缩成一个SELECT
:
SELECT DISTINCT ON (coalesce(t2_id, t1_id), t2_id)
t1_id, t2_id
FROM t0
ORDER BY coalesce(t2_id, t1_id), t2_id, t1_id;
Run Code Online (Sandbox Code Playgroud)
等效,但排序顺序除外。如果您希望速度更快,请尝试使用函数索引:
CREATE INDEX t0_func_idx ON t0 (coalesce(t2_id, t1_id), t2_id, t1_id);
Run Code Online (Sandbox Code Playgroud)