我正在针对包含时间序列中的一堆点的表开发查询.该表可能会变得非常大,因此我希望查询通过在固定时间间隔内平均点来有效地对输出进行下采样.编写查询后,我对sql Server(2008)如何选择执行查询感到惊讶.执行计划揭示了一种不必要的排序操作,随着时间序列的增长,这种操这是问题,简化为一个简单的例子:
CREATE TABLE [dbo].[Example] ( [x] FLOAT NOT NULL,[y] FLOAT NOT NULL,PRIMARY KEY CLUSTERED ( [x] ASC ) ); SELECT FLOOR([x]),AVG([y]) FROM [dbo].[Example] GROUP BY FLOOR([x]);
这里我有(x,y)对已经按x排序(由于聚集主键),我对每个整数x求平均值y(通过FLOOR函数截断).我希望该表已经适合于聚合,因为FLOOR是单调函数.不幸的是,sql Server决定需要重新排序这些数据,这是执行计划:
sql Server是否能够对已经适当排序的列的单调函数分组的数据执行流聚合?
是否有一般方法来重写此类查询,以便sql Server将看到订单被保留?
[更新]
我发现了一篇关于主题Things SQL needs: sargability of monotonic functions的文章,正如标题所示,似乎这是sql Server尚未做的优化(在大多数情况下).
这里甚至比[dbo]更简单的查询.[示例]证明了这一点:
SELECT [x],[y] FROM [dbo].[Example] ORDER BY FLOOR([x]) --sort performed in execution plan SELECT [x],[y] FROM [dbo].[Example] ORDER BY 2*[x] --NO sort performed in execution plan SELECT [x],[y] FROM [dbo].[Example] ORDER BY 2*[x]+1 --sort performed in execution plan
在任何单个添加或乘法中,查询优化器都会理解数据已经具有相同的顺序(当您按这样的表达式进行分组时也会看到这种情况).因此,似乎优化器可以理解单调函数的概念,而不是通常应用的.
解决方法
一些说明:
>当表为空时看到的计划和表有X行的计划可以是完全不同的计划
>我不认为在X字段上拥有主键是正确的.可以有两个具有相同X值的点吗?
create table Point ( PointId int identity(1,1) constraint PK_Example_Id primary key,X float not null,Y float not null,FloorX as floor(x) persisted ) create index IX_Point_FloorX_Y on Point(FloorX,Y)
添加一些行:
declare @RowCount int = 10000 while(@RowCount > 0) begin insert Point values (cast(crypt_gen_random(2) as int),cast(crypt_gen_random(2) as int)) set @RowCount -= 1 end
查询:
select floor(X),avg(Y) from Point group by floor(X)
要么
select FloorX,avg(Y) from Point group by FloorX
两者都有相同的计划
计划:没有排序
另一个选项 – 您可以创建索引视图.在这种情况下,您将不得不直接查询视图,除非您有Enterprise Edition,即使您直接查询表,它也会使用索引视图索引.
[编辑]刚才意识到我没有明确回答你的问题.你问为什么如果X是集群主键,sql会执行排序. sql不对X执行排序,它在floor(x)上执行排序.换句话说,如果x已经排序,那么f(x)不一定具有相同的顺序,对吧?