MS SQL 服务器是否将重复的聚合合并到单个查询中?
Does MS SQL Server consolidate repeated aggregates within a single query?
我正在对一些聚合密集型查询进行性能调优,我想知道一遍又一遍地重复相同的聚合函数是否会显着降低性能。
我假设 MS SQL 服务器足够智能,可以只计算每个重复聚合一次,然后每次在同一查询中遇到精确聚合时重复使用结果值 - 我的假设在这里是否正确?
对此的替代方法是,我们可以向该视图添加更多的连接(一遍又一遍地连接相同的表),使用不同的 join on
子句,将行组合成一堆不同的在不重复使用任何聚合函数的情况下生成各种总数的方法 - 但是查看执行计划我们可以看到添加更多连接肯定 确实 会使查询花费更长的时间,而且我们在技术上已经无论如何都有我们需要的所有信息和当前的连接数(我们只需要执行加法来产生复合总数)。
这是一些示例代码,来自其中一个有问题的视图:
COUNT_BIG ( [UVCE]. [ID] ) AS [TotalU] ,
COUNT_BIG ( [SVCE]. [ID] ) AS [TotalS] ,
COUNT_BIG ( [TVCE]. [ID] ) AS [TotalT] ,
COUNT_BIG ( [CVCE]. [ID] ) AS [TotalC] ,
COUNT_BIG ( [WVCE]. [ID] ) AS [TotalW] ,
/* More individual totals, etc. */
COUNT_BIG ( [SCE]. [ID] ) +
COUNT_BIG ( [TCE]. [ID] ) +
COUNT_BIG ( [CCE]. [ID] ) +
COUNT_BIG ( [WCE]. [ID] ) +
COUNT_BIG ( [UVCE]. [ID] ) +
COUNT_BIG ( [SVCE]. [ID] ) +
COUNT_BIG ( [TVCE]. [ID] ) +
COUNT_BIG ( [CVCE]. [ID] ) +
COUNT_BIG ( [WVCE]. [ID] ) AS [OverallTotal] ,
CASE WHEN COUNT_BIG ( [SCE]. [ID] ) +
COUNT_BIG ( [TCE]. [ID] ) +
COUNT_BIG ( [CCE]. [ID] ) +
COUNT_BIG ( [WCE]. [ID] ) +
COUNT_BIG ( [UVCE]. [ID] ) +
COUNT_BIG ( [SVCE]. [ID] ) +
COUNT_BIG ( [TVCE]. [ID] ) +
COUNT_BIG ( [CVCE]. [ID] ) +
COUNT_BIG ( [WVCE]. [ID] ) >= 64 THEN 4E0 ELSE (
COUNT_BIG ( [SCE]. [ID] ) +
COUNT_BIG ( [TCE]. [ID] ) +
COUNT_BIG ( [CCE]. [ID] ) +
COUNT_BIG ( [WCE]. [ID] ) +
COUNT_BIG ( [UVCE]. [ID] ) +
COUNT_BIG ( [SVCE]. [ID] ) +
COUNT_BIG ( [TVCE]. [ID] ) +
COUNT_BIG ( [CVCE]. [ID] ) +
COUNT_BIG ( [WVCE]. [ID] ) )
/ ( 64 / 4E0 ) END AS [Score]
SQL 服务器优化器非常好。
但是,您在使用聚合函数时遗漏了一个重点。通常,group by
子句比聚合函数调用要昂贵得多。也就是说,四处移动数据以定义组是查询的昂贵部分。 (一个例外是 count(distinct)
。)
也就是说,进行数十次函数调用会对性能产生显着影响。在 SQL 服务器中,使用常见的 table 表达式 (CTE) 或子查询在一个级别定义值并在另一级别使用它们非常容易。也就是说,SQL 服务器可能会为您执行此操作。我只是认为查询的其他部分在性能方面可能更为重要。
我正在对一些聚合密集型查询进行性能调优,我想知道一遍又一遍地重复相同的聚合函数是否会显着降低性能。
我假设 MS SQL 服务器足够智能,可以只计算每个重复聚合一次,然后每次在同一查询中遇到精确聚合时重复使用结果值 - 我的假设在这里是否正确?
对此的替代方法是,我们可以向该视图添加更多的连接(一遍又一遍地连接相同的表),使用不同的 join on
子句,将行组合成一堆不同的在不重复使用任何聚合函数的情况下生成各种总数的方法 - 但是查看执行计划我们可以看到添加更多连接肯定 确实 会使查询花费更长的时间,而且我们在技术上已经无论如何都有我们需要的所有信息和当前的连接数(我们只需要执行加法来产生复合总数)。
这是一些示例代码,来自其中一个有问题的视图:
COUNT_BIG ( [UVCE]. [ID] ) AS [TotalU] ,
COUNT_BIG ( [SVCE]. [ID] ) AS [TotalS] ,
COUNT_BIG ( [TVCE]. [ID] ) AS [TotalT] ,
COUNT_BIG ( [CVCE]. [ID] ) AS [TotalC] ,
COUNT_BIG ( [WVCE]. [ID] ) AS [TotalW] ,
/* More individual totals, etc. */
COUNT_BIG ( [SCE]. [ID] ) +
COUNT_BIG ( [TCE]. [ID] ) +
COUNT_BIG ( [CCE]. [ID] ) +
COUNT_BIG ( [WCE]. [ID] ) +
COUNT_BIG ( [UVCE]. [ID] ) +
COUNT_BIG ( [SVCE]. [ID] ) +
COUNT_BIG ( [TVCE]. [ID] ) +
COUNT_BIG ( [CVCE]. [ID] ) +
COUNT_BIG ( [WVCE]. [ID] ) AS [OverallTotal] ,
CASE WHEN COUNT_BIG ( [SCE]. [ID] ) +
COUNT_BIG ( [TCE]. [ID] ) +
COUNT_BIG ( [CCE]. [ID] ) +
COUNT_BIG ( [WCE]. [ID] ) +
COUNT_BIG ( [UVCE]. [ID] ) +
COUNT_BIG ( [SVCE]. [ID] ) +
COUNT_BIG ( [TVCE]. [ID] ) +
COUNT_BIG ( [CVCE]. [ID] ) +
COUNT_BIG ( [WVCE]. [ID] ) >= 64 THEN 4E0 ELSE (
COUNT_BIG ( [SCE]. [ID] ) +
COUNT_BIG ( [TCE]. [ID] ) +
COUNT_BIG ( [CCE]. [ID] ) +
COUNT_BIG ( [WCE]. [ID] ) +
COUNT_BIG ( [UVCE]. [ID] ) +
COUNT_BIG ( [SVCE]. [ID] ) +
COUNT_BIG ( [TVCE]. [ID] ) +
COUNT_BIG ( [CVCE]. [ID] ) +
COUNT_BIG ( [WVCE]. [ID] ) )
/ ( 64 / 4E0 ) END AS [Score]
SQL 服务器优化器非常好。
但是,您在使用聚合函数时遗漏了一个重点。通常,group by
子句比聚合函数调用要昂贵得多。也就是说,四处移动数据以定义组是查询的昂贵部分。 (一个例外是 count(distinct)
。)
也就是说,进行数十次函数调用会对性能产生显着影响。在 SQL 服务器中,使用常见的 table 表达式 (CTE) 或子查询在一个级别定义值并在另一级别使用它们非常容易。也就是说,SQL 服务器可能会为您执行此操作。我只是认为查询的其他部分在性能方面可能更为重要。