带窗口函数的简单SQL查询优化
Posted
技术标签:
【中文标题】带窗口函数的简单SQL查询优化【英文标题】:Optimization of simple SQL query with window function 【发布时间】:2014-09-17 16:45:48 【问题描述】:我有一个 PostgreSQL 表构造为
a | b | c
-----+-----+-----
3 | 2 | 1
1 | 5 | 1
8 | 4 | 1
2 | 5 | 1
4 | 4 | 2
2 | 5 | 2
9 | 3 | 2
3 | 5 | 3
2 | 5 | 3
4 | 4 | 3
5 | 6 | 3
9 | 7 | 3
我想为c
的每个值计算a
的平均值,其中b
低于给定值——例如b
的平均值。
这是我的查询:
SELECT avg(a) FROM mytable t WHERE b<(SELECT avg(b) FROM mytable WHERE c=t.c) GROUP BY c;
我实际上有两个问题,但我相信它们都属于这个问题(第一个问题实际上允许我更新标题):
这种查询是否有特定的名称或表达式(我的意思是,主查询中的子选择和重新集成操作,或类似的东西)?我什至找不到如何在线搜索解决方案... => 好的,窗口函数。
这个查询很慢,如何优化?我使用的是 9.3.5,b
已经按数字顺序排序。
谢谢。
更新:编辑 user17130 的答案 was rejected,但这个答案不会从头开始工作,所以这里是工作代码:
explain select
avg(a)
from
(
select
avg(b) over (partition by c) as b_avg,
a,
b,
c
from mytable
) as t
where b<b_avg
group by c;
QUERY PLAN
------------------------------------------------------------------------------------
GroupAggregate (cost=135.34..202.46 rows=67 width=8)
Subquery Scan on t (cost=135.34..198.39 rows=647 width=8)
Filter: ((t.b)::numeric < t.b_avg)
-> WindowAgg (cost=135.34..169.29 rows=1940 width=12)
-> Sort (cost=135.34..140.19 rows=1940 width=12)
Sort Key: mytable.c
-> Seq Scan on mytable (cost=0.00..29.40 rows=1940 width=12)
【问题讨论】:
查看窗口函数和 HAVING 子句。 搜索正确的术语确实要容易得多,谢谢!我会相应地更新问题。 发布解释分析(首选使用 explain.depesz.com)。 “非常慢”有点太模糊了。 【参考方案1】:我认为这就是你的意思。这只有一个使用窗口函数的表扫描。正如您所看到的,您在下面的查询估计比这个要花费更多的运行时间。如果没有任何选择性条件,您将至少扫描一次表。
explain select
a_avg
from
(
select
avg(a) over (partition by c) as a_avg
,avg(b) over (partition by c) as b_avg
,c
,b
from mytable
) as t
where b < b_avg
;
QUERY PLAN
──────────────────────────────────────────────────────────────────────────────
Subquery Scan on t (cost=135.34..203.24 rows=647 width=32)
Filter: ((t.b)::numeric < t.b_avg)
-> WindowAgg (cost=135.34..174.14 rows=1940 width=12)
-> Sort (cost=135.34..140.19 rows=1940 width=12)
Sort Key: mytable.c
-> Seq Scan on mytable (cost=0.00..29.40 rows=1940 width=12)
Planning time: 0.128 ms
(7 rows)
...
crow@test=# explain SELECT avg(a) FROM mytable t WHERE b<(SELECT avg(b) FROM mytable WHERE c=t.c) GROUP BY c;
QUERY PLAN
─────────────────────────────────────────────────────────────────────────────
HashAggregate (cost=66560.08..66560.92 rows=67 width=8)
Group Key: t.c
-> Seq Scan on mytable t (cost=0.00..66556.85 rows=647 width=8)
Filter: ((b)::numeric < (SubPlan 1))
SubPlan 1
-> Aggregate (cost=34.28..34.29 rows=1 width=4)
-> Seq Scan on mytable (cost=0.00..34.25 rows=10 width=4)
Filter: (c = t.c)
Planning time: 0.191 ms
(9 rows)
【讨论】:
您的代码并没有完全按照我的预期从头开始,但是您的回答非常有帮助,所以我用更正的代码对其进行了编辑。 编辑被拒绝,查看工作代码的更新问题。以上是关于带窗口函数的简单SQL查询优化的主要内容,如果未能解决你的问题,请参考以下文章
SQL 逻辑优化 case when 转为 union all