查询优化 TSQL 和其他

Posted

技术标签:

【中文标题】查询优化 TSQL 和其他【英文标题】:Query Optimization TSQL and otherwise 【发布时间】:2009-02-12 18:12:45 【问题描述】:

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

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

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

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

【问题讨论】:

你确定你需要把时间花在那些事情上吗?看看卢克关于 SQL 是什么和不是什么的回答......并尝试更广泛地看待这个问题:如果这样一个简单的查询对你来说是一个问题,也许你调用它太多次...... 很确定他只是用这个作为一个理论例子来证明他的观点/问题,即你是否可以使用 SQL 优化器的变量查询...... 【参考方案1】:

简短的回答...

是的,优化器足够聪明。

更长的答案...

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

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

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

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

【讨论】:

【参考方案2】:

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

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

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

【讨论】:

是的,这就是我的想法,但这可能取决于实现。 问题是优化器是否自动执行此操作,我提到我确实测试过它,结果不确定... 如果更改顺序会更改查询计划,那么您就有了一个 tinkertoy 优化器。 le dorfier,你是对的,它绝对应该。尽管与 C#/Java 等语言的短路总是从左到右发生,这是一个有趣的对比。【参考方案3】:

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

SELECT FIELDLIST 
FROM TABLE 
WHERE 
(FIELD = @FOO)

UNION

SELECT FIELDLIST 
FROM TABLE 
WHERE 
(@FOO IS NULL)

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

【讨论】:

+1 因为这也是我的经验。也就是说,我建议使用UNION ALL,否则你有一个隐含的DISTINCT 会超过最终结果。【参考方案4】:

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

【讨论】:

【参考方案5】:

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

【讨论】:

以上是关于查询优化 TSQL 和其他的主要内容,如果未能解决你的问题,请参考以下文章

查询优化怎样用SQL语句查看查询的性能指标

sql优化:通过子查询或自己的查询计算所有行/其他改进

用于计数和显示(列中的不同值)的 Sql 查询优化,按其他两列分组

SQL UDF 和查询优化 [重复]

MySQL索引优化与查询优化(重点:索引失效的11种情况)

运行时查询分析和优化