Sql server 避免SQL Server GROUP BY中不必要的排序?
我有数据样本表,带有时间戳和一些数据。每个表在时间戳上都有一个聚集索引,然后是一个特定于数据的键。数据样本不一定是等距的 我需要在一个特定的时间范围内对数据进行下采样,以便绘制图表——比如,从100000行到N,其中N约为50。虽然从DSP的角度来看,我可能不得不在算法的“正确性”上做出妥协,但出于性能原因,我希望将其保留在SQL中 我目前的想法是将时间范围内的样本分组到N个框中,然后取每组的平均值。在SQL中实现这一点的一种方法是对从0到N-1(包括)的日期应用分区函数,然后按和平均分组 我认为这个GROUPBY可以在没有排序的情况下执行,因为日期来自聚集索引,并且分配函数是单调的。然而,SQLServer似乎没有注意到这一点,它发出的排序表示78%的执行成本(在下面的示例中)。假设我是对的,并且这种排序是不必要的,我可以使查询速度提高5倍 有没有办法强制SQL Server跳过排序?还是有更好的方法来解决这个问题 干杯。 本Sql server 避免SQL Server GROUP BY中不必要的排序?,sql-server,sorting,group-by,Sql Server,Sorting,Group By,我有数据样本表,带有时间戳和一些数据。每个表在时间戳上都有一个聚集索引,然后是一个特定于数据的键。数据样本不一定是等距的 我需要在一个特定的时间范围内对数据进行下采样,以便绘制图表——比如,从100000行到N,其中N约为50。虽然从DSP的角度来看,我可能不得不在算法的“正确性”上做出妥协,但出于性能原因,我希望将其保留在SQL中 我目前的想法是将时间范围内的样本分组到N个框中,然后取每组的平均值。在SQL中实现这一点的一种方法是对从0到N-1(包括)的日期应用分区函数,然后按和平均分组 我认
是的,SQLServer在这种时间分区方面总是有一些问题。AnalysisServices有各种各样的方法来处理它,但数据服务方面更为有限
我建议您尝试(我不能在这里尝试或测试任何东西)创建一个包含您的分区定义的辅助“分区表”,然后针对它进行连接。您需要一些匹配索引才能让his有机会工作:SQL Server真的不可能知道
日期
聚集键可以用于round(cast..as float)之类的表达式来保证顺序。只有这样,它才会偏离轨道。加上(…-@min)*@scale
,你就把自己弄得一团糟。如果需要按这些表达式进行排序和分组,请将它们存储在持久化的计算列中,并按它们进行索引。您可能希望使用DATEPART
,但使用诸如float之类的不精确类型可能会导致表达式无法用于持久化的计算列
更新
关于日期
和浮动
等效的主题:
declare @f float, @d datetime;
select @d = cast(1 as datetime);
select @f = cast(1 as float);
select cast(@d as varbinary(8)), cast(@f as varbinary(8)), @d, cast(@d as float)
产生以下结果:
0x0000000100000000 0x3FF0000000000000 1900-01-02 00:00:00.000 1
因此,您可以看到,尽管它们都存储在8个字节(至少是浮点(25…53)
)上,日期时间的内部表示形式不是浮点
,整数部分是天,小数部分是时间(通常假设)
再举一个例子:
declare @d datetime;
select @d = '1900-01-02 12:00 PM';
select cast(@d as varbinary(8)), cast(@d as float)
0x0000000100C5C100 1.5
同样,将@d
转换为float
的结果是1.5
,但是0x0000000100C5C100
的日期时间内部表示将是IEEE双值2.1284E-314
,而不是1.5
两个问题:
这个查询需要多长时间
你确定它正在排序日期吗?另外,在计划中,它在哪里对日期进行排序?之后呢?那是我的猜测。我怀疑这和它做的第一件事一样。。。也许它需要重新进行排序
无论如何,即使它确实对已经排序的列表进行了排序,它也不会认为需要很长时间,因为它已经进行了排序…在本例中,至少应该很容易分析(…-@min)*@scale部分。不幸的是,将“date”列存储为float似乎没有什么区别。不过,说到底,您是对的:希望SQLServer自动解决这个问题有点乐观。我真正希望的是一种方法,让它假设数据已经排序。:)关于FLOAT的不精确性,我认为DATETIME在内部只是一个FLOAT?啊,这很有趣!谢谢
declare @d datetime;
select @d = '1900-01-02 12:00 PM';
select cast(@d as varbinary(8)), cast(@d as float)
0x0000000100C5C100 1.5