sql-server - 按单调函数分组的聚合的冗余排序

标签 sql-server tsql sql-server-2008 aggregate-functions

我正在针对包含时间序列中的一堆点的表开发一个查询。该表可能会变得非常大,因此我希望查询通过对固定时间间隔内的点进行平均来有效地对输出进行下采样。编写查询后,我对 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 决定需要对这些数据重新排序,执行计划如下:

Example Execution Plan

SQL Server 不应该能够对按已适当排序的列的单调函数分组的数据执行流式聚合吗?

有没有通用的方法来重写此类查询,以便 SQL Server 看到顺序被保留?

[更新] 我找到了一篇关于该主题的文章 Things SQL needs: sargability of monotonic functions而且,正如标题所示,这似乎是 SQL Server 尚未执行的优化(在大多数情况下)。

下面是通过 [dbo].[Example] 进行的更简单的查询,演示了这一点:

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

两者都有相同的计划

计划:无排序

enter image description here

另一个选项 - 您可以创建索引 View 。在这种情况下,您将必须直接查询 View ,除非您有企业版,即使您直接查询表,企业版也会使用索引 View 索引。

[编辑]刚刚意识到我没有明确回答您的问题。您问如果X是聚集主键,SQL为什么要执行排序。 SQL 不对X 执行排序,而是对floor(x) 执行排序。换句话说,如果 x 已经排序,那么 f(x) 不一定具有相同的顺序,对吧?

关于sql-server - 按单调函数分组的聚合的冗余排序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6319020/

相关文章:

sql - 我是否需要在外键上指定 ON DELETE NO ACTION?

php - 如果产品有条码并且所有产品都没有条码,则按产品条码进行分组的SQL查询

sql - 索引 View 和执行计划

database - 从 execute(@query) 中选择 * 进入#table

sql-server - 简单私有(private)消息的数据库设计

sql - 使用上下文连接时不需要将 null 转换为 DBNull

c# - 在 SQL LIKE 子句中使用 SqlParameter 不起作用

c# - 这是一条什么样的路呢?

sql-server-2008 - 如何从另一个没有临时表的存储过程调用一个存储过程(带参数)

sql - 如何检索表中两个特定列中的值不同的所有行