dsd*_*dsd 2 sql postgresql aggregate-functions postgresql-9.3
我正在使用Postgres 9.3.
我有两张桌子T1 和它们之间T2的n:m关系T1_T2_rel.现在我想创建一个视图,除了T1的列之外,还提供了一个列,对于T1中的每个记录,该列包含一个数组,其中包含T2的所有相关记录的主键ID.如果T2中没有相关条目,则该列的相应字段应包含空值.
我的架构的抽象版本如下所示:
CREATE TABLE T1 ( t1_id serial primary key, t1_data int );
CREATE TABLE T2 ( t2_id serial primary key );
CREATE TABLE T1_T2_rel (
t1_id int references T1( t1_id )
, t2_id int references T2( t2_id )
);
Run Code Online (Sandbox Code Playgroud)
相应的样本数据可以生成如下:
INSERT INTO T1 (t1_data)
SELECT cast(random()*100 as int) FROM generate_series(0,9) c(i);
INSERT INTO T2 (t2_id) SELECT nextval('T2_t2_id_seq') FROM generate_series(0,99);
INSERT INTO T1_T2_rel
SELECT cast(random()*10 as int) % 10 + 1 as t1_id
, cast(random()*99+1 as int) as t2_id
FROM generate_series(0,99);
Run Code Online (Sandbox Code Playgroud)
到目前为止,我已经提出了以下查询:
SELECT T1.t1_id, T1.t1_data, agg
FROM T1
LEFT JOIN LATERAL (
SELECT t1_id, array_agg(t2_id) as agg
FROM T1_T2_rel
WHERE t1_id=T1.t1_id
GROUP BY t1_id
) as temp ON temp.t1_id=T1.t1_id;
Run Code Online (Sandbox Code Playgroud)
这有效.但是,它可以简化吗?
相应的小提琴可以在这里找到:sql-fiddle.不幸的是,sql-fiddle不支持Postgres 9.3(尚未),这是横向连接所必需的.
[ 更新 ]正如已经指出的那样,left join原则上使用子查询的简单就足够了.但是,如果我比较查询计划,Postgres会在使用a时对聚合表进行顺序扫描,left join而在使用的情况下使用索引扫描left join lateral.
正如@Denis已经评论过:没必要LATERAL.此外,您的子查询选择了错误的列.这有效:
SELECT t1.t1_id, t1.t1_data, t2_ids
FROM t1
LEFT JOIN (
SELECT t1_id, array_agg(t2_id) AS t2_ids
FROM t1_t2_rel
GROUP BY 1
) sub USING (t1_id);
Run Code Online (Sandbox Code Playgroud)
关于随后的顺序扫描,您提到:如果查询整个表,顺序扫描通常会更快.取决于您运行的版本,硬件,设置以及基数和数据分布的统计信息.尝试选择性WHERE条款,如WHERE t1.t1_id < 1000或WHERE t1.t1_id = 1000与计划器设置结合,以了解选择:
SET enable_seqscan = off;
SET enable_indexscan = off;
Run Code Online (Sandbox Code Playgroud)
重置:
RESET enable_seqscan;
RESET enable_indexscan;
Run Code Online (Sandbox Code Playgroud)
只有在你当地的会议中,请注意!关于dba.SE的相关答案有更多说明.
当然,您的设置也可能已关闭:
| 归档时间: |
|
| 查看次数: |
3910 次 |
| 最近记录: |