聚合分组单调函数的冗余排序

如何解决聚合分组单调函数的冗余排序

| 我正在针对包含时间序列中许多点的表开发查询。该表可能会变得很大,因此我希望查询通过对固定时间间隔内的点进行平均来有效地对输出进行下采样。编写查询后,我对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
函数截断)。由于expect1ѭ是单调函数,我希望该表已针对聚集进行适当排序。不幸的是,SQL Server决定需要对这些数据进行重新排序,这是执行计划: SQL Server是否应该能够对按已适当排序的列的单调函数分组的数据执行流式聚合? 是否存在重写此类查询的通用方法,以便SQL Server可以看到顺序已保留? [更新] 我找到了一篇有关SQL需要的主题的文章:单调函数的可维护性,正如标题所示,这似乎是SQL Server尚未进行的优化(在大多数情况下)。 以下是通过ѭ3进行的更简单的查询,证明了这一点:
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,即使直接查询表也将使用索引视图索引。 [编辑]刚刚意识到我没有明确回答您的问题。您问如果ѭ9是集群主键,为什么SQL会执行排序。 SQL不对ѭ9进行排序,而是对ѭ11进行排序。换句话说,如果已经对
x
进行了排序,那么
f(x)
不一定具有相同的顺序,对吗?     ,        当索引列上有任何功能时,SQL Server几乎总是忽略索引。有充分的理由: 查询优化器(QO)使用数据分布的统计信息。 该函数改变了这一点:您希望每个查询生成统计信息吗? 该函数(在这种情况下,肯定是)可以使索引的唯一性无效 QO可以在其计划生成中使用唯一性 一些优化已被编码到QO中(例如:IF中的COUNT vs EXISTS),但它没有严格的数学证明:它们不适用于查询响应时间 也有一些日期时间函数的MS Connect(我实际上不同意,因为有太多的函数排列无法优化:所以我们会有不一致的地方) 否则,我会做Alex Aza的索引计算列解决方案 编辑: 阅读更新问题中的链接。 地板严格从单调变为单调。也就是说,x是唯一的,因此严格单调。 FLOOR(x)是单调的。 如果您有WHERE子句,统计信息就变得很重要:正如您所说的,您发布了简化的示例。 对于您发布的x * 2 +1示例:您认为SQL Server应该在什么时候停止对表达式求值?当然,这是基于成本的优化器。 我认为SQL Server的行为是这样的:每天我的EXISTS优化示例都非常有用。     ,这个问题问得好。在这种情况下,我们希望有另一个表并使用CROSS APPLY,例如以下示例,该表使用表Numbers存储所有在Min(X)/ YourStepInMinutes和Max(x)/ YourStepInMinutes之间的数字,以及在Min和X周围另外两个数字最高该查询作为嵌套循环运行,不需要排序:
SELECT n.n,Avg(p.y)
FROM dbo.Numbers AS n
CROSS APPLY (SELECT p.y 
  FROM dbo.Points AS p 
  WHERE p.x<n*YourStepInMinutes AND (n-1)*YourStepInMinutes<=p.x
) As p
编辑:虽然此解决方案确实需要一个不是免费的联接,但我不会发表总会很慢的声明。排序大量数据可能突然变得非常慢-您对行的排序量增加了10%,而排序速度可能慢了10倍。另一方面,此方法可扩展性更好,因为它不需要很大的种类。 另外,因为我们不需要持久化的计算列,所以我们可以立即对任何大小的间隔(例如17分钟)使用此查询。     

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-