我有一个包含约 5,000,000 行 SCADA 数据的表,描述如下:
创建表数据(o int,m Money)
。
地点:
- o
是带有聚集索引的 PK。 o
的填充因子接近 100%。 o
代表抄表日期,可以认为是X轴。
- m
是位于 1..500
区域内的十进制值,实际仪表读数可以视为 Y 轴。
我需要找出某些模式,即它们发生的时间、频率和持续时间。
示例。查找 m
在 5
内by将区域从 500
更改为 510
的所有出现情况> 单位(从 1 到 5)o
我运行以下查询:
select d0.o as tFrom, d1.o as tTo, d1.m - d0.m as dValue
from data d0
inner join data d1
on (d1.o = d0.o + 1 or d1.o = d0.o + 2 or d1.o = d0.o + 3 or d1.o = d0.o + 4)
and (d1.m - d0.m) between 500 and 510
执行查询需要 23
秒。
以前的版本花了 30
分钟(慢了 90 倍),我设法使用简单的方法对其进行了优化,方法是将: on (d1.o - d0.o) 替换为 1 和4
with on (d0.o = d1.o - 1 或 d0.o = d1.o - 2 或 d0.o = d1.o - 3 或 d0.o = d1.o - 4 )
我很清楚为什么它更快 - 一方面,索引列扫描应该在另一方面足够快地 fork ,因为日期是离散的,所以我可以负担得起(并且我总是给任何5
分钟的宽限时间o
区域,因此 120
分钟内为 115..120
区域)。我不能对 m
值使用相同的方法,因为它们是不可分割的。
到目前为止我尝试过的事情:
通过在脚本底部应用 @oRegionStart 和 @oRegionEnd 之间的
where o
进行软分片。并在循环中运行它,将结果提取到临时表中。执行时间 -25
秒。通过将数据拆分到多个物理表中来进行硬分片。结果是
2
分钟,不用担心维护麻烦。使用一些预先准备好的数据结构,例如:
创建表 data_change_matrix (o int, dM5Min 金钱, dM5Max 金钱, dM10Min 金钱, dM10Max 金钱 ... dM{N}Min 金钱, dM{N}Max 金钱)
其中N
是我运行分析的最大部门。有了这样的表,我可以轻松编写查询:
从 data_change_matrix 中选择 *,其中 dMin5Min 介于 500 和 510 之间
结果是 - 由于巨大的尺寸要求(5M X ~ 250)和维护相关成本,它毫无进展,我需要接近实时地支持该矩阵现实。
SQL CLR
- 甚至不要问我出了什么问题,它就是无法解决问题。
现在我失去了灵感并寻求帮助。
总而言之 - 在大量数据上运行此类类型的查询是否有可能获得接近即时的响应时间?
所有内容都在 MS Sql Server 2012 上运行。没有在 MS Sql Server 2014 上尝试,但如果有意义的话,我很乐意这样做。
更新 - 执行计划:http://pastebin.com/PkSSGHvH .
更新 2 - 虽然我真的很喜欢 usr 建议的 LAG 功能,但我想知道是否有 LAG**S** 功能允许
select o, MIN(LAG**S**(o, 4)) over(...) - 或者 TSL 中最短的实现是什么?
我使用 SQL CLR 尝试了非常类似的方法并使其工作,但性能很糟糕。
最佳答案
我假设你的意思是写“on (d1.o = ...”而不是“on (d.o = ...”)。无论如何,我通过简化语句(使我猜查询优化器会选择更好的计划):
select d0.o as tFrom, d1.o as tTo, d1.m - d0.m as dValue
from data d0
inner join data d1
on d1.o between d0.o + 1 and d0.o + 4
and (d1.m - d0.m) between 500 and 510
祝您的查询顺利!
关于sql - MS Sql Server 2012 的查询优化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25060968/