Sql 有没有比';无界前一行和当前行之间的行';
我有以下数据库表:Sql 有没有比';无界前一行和当前行之间的行';,sql,postgresql,postgresql-performance,Sql,Postgresql,Postgresql Performance,我有以下数据库表: date a b c d add result 23.02.07 A B C1 D1 1 1 24.02.07 A B C1 D1 0 1 25.02.07 A B C1 D1 1 2 26.02.07 A B C1 D1 1 3 27.02.07 A B C1 D1 1 4 28.02.07 A B C1 D1 0
date a b c d add result
23.02.07 A B C1 D1 1 1
24.02.07 A B C1 D1 0 1
25.02.07 A B C1 D1 1 2
26.02.07 A B C1 D1 1 3
27.02.07 A B C1 D1 1 4
28.02.07 A B C1 D1 0 4
01.03.07 A B C1 D1 0 4
02.03.07 A B C1 D1 0 4
03.03.07 A B C1 D1 1 5
04.03.07 A B C1 D1 0 5
05.03.07 A B C1 D1 0 5
06.03.07 A B C1 D1 0 5
07.03.07 A B C1 D1 2 7
17.02.07 A B C2 D2 1 1
18.02.07 A B C2 D2 0 1
19.02.07 A B C2 D2 0 1
20.02.07 A B C2 D2 0 1
21.02.07 A B C2 D2 0 1
22.02.07 A B C2 D2 0 1
23.02.07 A B C2 D2 0 1
24.02.07 A B C2 D2 0 1
25.02.07 A B C2 D2 1 2
26.02.07 A B C2 D2 3 5
27.02.07 A B C2 D2 1 6
28.02.07 A B C2 D2 0 6
列结果(最后一个)不是实际数据集的一部分。本专栏展示了我正在努力实现的目标。
基本上,我是通过使用下面的分析函数,将给定分区中所有先前的“add”值和当前值相加:
SUM(add) OVER(PARTITION BY
A,
B,
C,
D,
ORDER BY date ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
) AS result
这种方法可以工作,但在查询大型数据集合时速度较慢
更多见解:
- 日期上有一个btree索引(不是日期数据类型,而是一个字符)
- 所有其他变量都是字符变量,而不是整数加法
- A和B也有一个B树索引
排序依据
不确定(多行的每个分区的日期相同)。使用前一行和当前行之间的帧定义,查询结果可以在调用之间更改
默认的帧定义是在无界的前一行和当前行之间的范围
,这对于您的情况可能更有意义:它按排序顺序(分区中的同一天)添加当前行的所有对等方,因此您可以在同一天获得分区中所有行的相同总数
使排序顺序具有确定性(例如,通过添加PK作为最后一个排序依据
项)或切换到范围
。由于默认值为前一行和当前行之间的范围,因此您可以简化:
SUM(add) OVER(PARTITION BY A, B, C, D ORDER BY date)
正确的日期
处理
这是不对的:
日期上有一个btree索引(不是日期数据类型,而是一个字符)
这是一个有后果的错误。永远不要将日期存储为varchar
,将日期存储为date
。即使“按日期排序”
恰好可以正确使用您的特定字符串格式(“23.02.07”就像您在问题中所说的那样,不),速度仍然较慢。而且容易出错。而且存储空间更大(因此也更慢)
性能优化
除此之外,索引列顺序匹配的多列索引可以提高性能():
您可以使用此索引对物理表进行群集,以获得更快的结果:
细节取决于完整的情况:Postgres版本、表定义、完整的查询,这应该已经是最快的方法了。您可以使用这个覆盖索引来加快速度,它已经按照所需的顺序包含了数据:create index idx_covering on mytable(a、b、c、d、date、add)代码>。请更具体地说明“大”和“慢”如何生成添加列?是否确定默认帧?我假设PostgreSQL支持标准SQL的默认值,您的链接也显示了它:默认的框架选项是RANGE UNBOUNDED<代码>范围
通常比行
要贵得多(即使由于唯一的顺序BY,结果是相同的),因此前面的行无边界
应该更好。@dnoeth:谢谢!你完全正确,我的疏忽<代码>范围
是默认值。我相应地修改了我的答案。不过,“更好”是由需求定义的。
CREATE INDEX foo ON tbl (A, B, C, D, date, add);