0

假设我有一个类似下面的 sql 语句,变量 @FOO 在代码的前面某处设置:

SELECT FIELDLIST 
FROM TABLE 
WHERE 
(FIELD = @FOO OR @FOO IS NULL)

查询优化器是否足够聪明,可以先执行 OR 的第二面(@FOO IS NULL),因为(另一个假设)执行空值检查比执行字段比较更快?

我做了一些非正式的基准测试,不仅没有看到差异,而且我的尝试得到了不同的结果时间,这使我无法进行适当的比较。

4

5 回答 5

3

简短的回答...

的,优化器足够聪明。

更长的答案...

SQL 是声明性的而不是命令性的:您的查询是对结果必须满足的条件的描述,而不是关于如何生成这些结果的分步说明。

优化器以最有效的顺序执行查询。它不能保证以任何特定的顺序评估您的条款,甚至根本评估它们 - 如果它可以在不评估特定条款的情况下获得正确的结果,那么它为什么要打扰呢?

任何特定查询的实际评估顺序是一个实现细节,并且可以随时间变化(例如,随着表的统计信息的变化)。

在实践中,优化器偶尔会出错,但在这种特殊情况下 - 将变量与 NULL 与从表或索引中读取进行比较 - 我认为它不太可能搞砸,尽管您可能想考虑使用OPTION(RECOMPILE)OPTION(OPTIMIZE FOR ...)

于 2009-02-12T23:54:50.340 回答
1

尝试使用相反顺序的子句对其进行测试:

SELECT FIELDLIST 
FROM TABLE 
WHERE 
(@FOO IS NULL OR FIELD = @FOO)

您可能会发现第一个测试会使第二个测试短路,但反之亦然。

于 2009-02-12T18:15:57.987 回答
1

根据我的经验,有时使用两个查询和一个“UNION”而不是“OR”子句会更快。

SELECT FIELDLIST 
FROM TABLE 
WHERE 
(FIELD = @FOO)

UNION

SELECT FIELDLIST 
FROM TABLE 
WHERE 
(@FOO IS NULL)

这种方法有重复 SELECT 语句的缺点,但是 1500% 的性能提升证明了它的合理性。当然,这取决于数据库结构(在我的情况下它非常糟糕,我无法更改它)。

于 2009-02-13T10:23:51.857 回答
0

首先应用更快的条件是足够聪明的,假设它可以判断在一般情况下哪个比较会更快。在这种情况下,NULL 检查几乎总是更快,因为它必须从表达式的每一侧最多比较一个字节,并且可以将其分解。

于 2009-02-12T18:14:51.763 回答
0

如果此查询位于存储过程中,则此处可能起作用的一个因素是“参数嗅探”。这可能导致不一致的查询响应时间。要解决此问题,请在 sproc 中声明一个内部变量并将此变量分配给参数值,然后在 where 子句中使用内部变量或在 sproc 中使用RECOMPILE子句。关于这个主题有很多链接。

于 2009-02-12T18:29:07.067 回答