GROUP BY 子句中 ISNULL() 的性能 SQL
Performance of ISNULL() in GROUP BY clause SQL
我最近一直在重构一些旧的查询,并注意到其中很多在 GROUP BY
子句中重复 ISNULL()
,而在 SELECT
子句中使用它。我骨子里觉得删除 GROUP BY
子句中的 ISNULL()
会提高性能,但我找不到任何文档来说明它是否真的可能。这是我的意思:
SELECT
ISNULL(Foo,-1) AS Foo
,ISNULL(Bar,-1) AS Bar
,SUM(This) AS This
,SUM(That) AS That
FROM
dbo.ThisThatTable AS ThisThat
LEFT JOIN dbo.FooBarTable AS FooBar ON ThisThat.FooBarId = FooBar.Id
GROUP BY
ISNULL(Foo,-1)
,ISNULL(Bar,-1);
GO
以上是我不断遇到的方式 - 当 Foo 列上有分组时,所选列的 SELECT
和 GROUP BY
完全匹配。下面的示例是一个可能的替代方案 - 一些可能不必要的 ISNULL()
调用已被删除,并且 SELECT
和 GROUP BY
子句不再匹配。
SELECT
ISNULL(Foo,-1) AS Foo
,ISNULL(Bar,-1) AS Bar
,SUM(This) AS This
,SUM(That) AS That
FROM
dbo.ThisThatTable AS ThisThat
LEFT JOIN dbo.FooBarTable AS FooBar ON ThisThat.FooBarId = FooBar.Id
GROUP BY
Foo
,Bar;
GO
我想也许当 SELECT 和 GROUP BY
子句匹配时,优化器只需要执行一次 ISNULL()
计算就知道发生了什么,所以理论上可能是按实际选择的结果分组更有表现力?或者,也许最好避免添加根本不改变数据粒度的第二组 ISNULL()
调用......也许优化器足够聪明,可以意识到分组中的 NULLS 是(在这种情况下)选择中的 -1s...?
我个人更愿意删除任何不必要的功能,尤其是那些可能会影响索引使用的功能,但是当我在线查看时,对性能的引用都像答案here,关于在中使用ISNULL()
WHERE
子句,我已经知道要避免。
我也怀疑任何收益都会微乎其微,所以这实际上是在寻求学术或理论答案,但在我工作的过程中,我一直在想,这让我很烦恼,所以我想我会问是否任何人都有任何想法。
Non-aggregated SELECT 子句中的列通常必须精确匹配 GROUP BY 子句中的列。如果我是你,并且我正在处理经过测试的生产代码,我不会进行你建议的更改。
编辑 non-aggregated SELECT 列和 GROUP BY 列之间的匹配对于 GROUP BY 是必需的。如果 SELECT 中的列 1:1 依赖于 GROUP BY 中的列,它将起作用。否则结果不明确。
在内部,SQL 并不是每个 ISNULL 都有两个副本。它们都在编译期间使用的内部树中一起展平。因此,在 SQL 服务器中考虑这种优化级别没有用。一个没有任何 ISNULL 的查询可能会执行得更快一些,并且可能会更快,具体取决于模式和查询的其余部分。但是,select 列表中的 ISNULL 和 GROUP BY 列表在大多数情况下不会在 SQL 中执行两次 - 这种详细程度可以显示在 showplan 中,但通常低于详细程度人们会关心检查。
这里有几个不同的方面需要考虑:
在同一范围内多次引用同一值
在大多数情况下,优化器足够聪明,可以将它们折叠成计算一次。事实上,你对它们的 GROUP BY
使这更有可能。
在保证值不为null的情况下分组是否更快?
可能吧,虽然我怀疑这种差异是可以衡量的。
SELECT
不必完全匹配,只需要功能依赖在GROUP BY
列和聚合函数上即可.它在功能上可能不依赖于任何其他列。
首要考虑的最重要的事情:索引。
这 比其他考虑因素 重要得多。分组的时候,如果你能命中一个索引,那么速度会快很多,因为它可以去掉排序,只用Stream Aggregate
。如果您在 GROUP BY
中使用 ISNULL
(除非计算列或索引视图),这是不可能的。
请注意,您的结果不会相同:第一个示例将 NULL
组折叠到 -1
组中。第二个示例没有,因此您可能还想从 SELECT
中删除 ISNULL
,以区分它们。或者,改用 WHERE ... IS NOT NULL
。
我最近一直在重构一些旧的查询,并注意到其中很多在 GROUP BY
子句中重复 ISNULL()
,而在 SELECT
子句中使用它。我骨子里觉得删除 GROUP BY
子句中的 ISNULL()
会提高性能,但我找不到任何文档来说明它是否真的可能。这是我的意思:
SELECT
ISNULL(Foo,-1) AS Foo
,ISNULL(Bar,-1) AS Bar
,SUM(This) AS This
,SUM(That) AS That
FROM
dbo.ThisThatTable AS ThisThat
LEFT JOIN dbo.FooBarTable AS FooBar ON ThisThat.FooBarId = FooBar.Id
GROUP BY
ISNULL(Foo,-1)
,ISNULL(Bar,-1);
GO
以上是我不断遇到的方式 - 当 Foo 列上有分组时,所选列的 SELECT
和 GROUP BY
完全匹配。下面的示例是一个可能的替代方案 - 一些可能不必要的 ISNULL()
调用已被删除,并且 SELECT
和 GROUP BY
子句不再匹配。
SELECT
ISNULL(Foo,-1) AS Foo
,ISNULL(Bar,-1) AS Bar
,SUM(This) AS This
,SUM(That) AS That
FROM
dbo.ThisThatTable AS ThisThat
LEFT JOIN dbo.FooBarTable AS FooBar ON ThisThat.FooBarId = FooBar.Id
GROUP BY
Foo
,Bar;
GO
我想也许当 SELECT 和 GROUP BY
子句匹配时,优化器只需要执行一次 ISNULL()
计算就知道发生了什么,所以理论上可能是按实际选择的结果分组更有表现力?或者,也许最好避免添加根本不改变数据粒度的第二组 ISNULL()
调用......也许优化器足够聪明,可以意识到分组中的 NULLS 是(在这种情况下)选择中的 -1s...?
我个人更愿意删除任何不必要的功能,尤其是那些可能会影响索引使用的功能,但是当我在线查看时,对性能的引用都像答案here,关于在中使用ISNULL()
WHERE
子句,我已经知道要避免。
我也怀疑任何收益都会微乎其微,所以这实际上是在寻求学术或理论答案,但在我工作的过程中,我一直在想,这让我很烦恼,所以我想我会问是否任何人都有任何想法。
Non-aggregated SELECT 子句中的列通常必须精确匹配 GROUP BY 子句中的列。如果我是你,并且我正在处理经过测试的生产代码,我不会进行你建议的更改。
编辑 non-aggregated SELECT 列和 GROUP BY 列之间的匹配对于 GROUP BY 是必需的。如果 SELECT 中的列 1:1 依赖于 GROUP BY 中的列,它将起作用。否则结果不明确。
在内部,SQL 并不是每个 ISNULL 都有两个副本。它们都在编译期间使用的内部树中一起展平。因此,在 SQL 服务器中考虑这种优化级别没有用。一个没有任何 ISNULL 的查询可能会执行得更快一些,并且可能会更快,具体取决于模式和查询的其余部分。但是,select 列表中的 ISNULL 和 GROUP BY 列表在大多数情况下不会在 SQL 中执行两次 - 这种详细程度可以显示在 showplan 中,但通常低于详细程度人们会关心检查。
这里有几个不同的方面需要考虑:
在同一范围内多次引用同一值
在大多数情况下,优化器足够聪明,可以将它们折叠成计算一次。事实上,你对它们的GROUP BY
使这更有可能。在保证值不为null的情况下分组是否更快?
可能吧,虽然我怀疑这种差异是可以衡量的。SELECT
不必完全匹配,只需要功能依赖在GROUP BY
列和聚合函数上即可.它在功能上可能不依赖于任何其他列。首要考虑的最重要的事情:索引。
这 比其他考虑因素 重要得多。分组的时候,如果你能命中一个索引,那么速度会快很多,因为它可以去掉排序,只用Stream Aggregate
。如果您在GROUP BY
中使用ISNULL
(除非计算列或索引视图),这是不可能的。
请注意,您的结果不会相同:第一个示例将 NULL
组折叠到 -1
组中。第二个示例没有,因此您可能还想从 SELECT
中删除 ISNULL
,以区分它们。或者,改用 WHERE ... IS NOT NULL
。