惊人的SQL速度提升

时间:2008-12-19 10:46:30

标签: sql performance

我刚刚发现以下两个select语句之间的执行计划性能差异很大:

select * from your_large_table
where LEFT(some_string_field, 4) = '2505'

select * from your_large_table
where some_string_field like '2505%'

执行计划分别为98%和2%。然后速度有点不同。我看到它时感到非常震惊。

我总是做好LEFT(xxx)='yyy',因为它读得很好。 我实际上通过检查LINQ生成的SQL来反对我手工制作的SQL来找到它。我假设LIKE命令会更慢,但实际上要快得多。

我的问题是为什么LEFT()比LIKE'%..'慢。他们毕竟是完全一样的吗?

此外,是否使用LEFT()?

命中CPU

7 个答案:

答案 0 :(得分:23)

更一般地说,在查询中不应该在WHERE子句的LEFT侧使用函数。如果这样做,SQL将不使用索引 - 它必须为表的每一行评估函数。目标是确保您的where子句为“Sargable

其他一些例子:

Bad: Select ... WHERE isNull(FullName,'') = 'Ed Jones'
Fixed: Select ... WHERE ((FullName = 'Ed Jones') OR (FullName IS NULL))

Bad: Select ... WHERE SUBSTRING(DealerName,4) = 'Ford'
Fixed: Select ... WHERE DealerName Like 'Ford%'

Bad: Select ... WHERE DateDiff(mm,OrderDate,GetDate()) >= 30
Fixed: Select ... WHERE OrderDate < DateAdd(mm,-30,GetDate()) 

Bad: Select ... WHERE Year(OrderDate) = 2003
Fixed: Select ... WHERE OrderDate >= '2003-1-1' AND OrderDate < '2004-1-1'

答案 1 :(得分:17)

看起来表达式LEFT(some_string_field,4)是针对全表扫描的每一行进行评估,而“like”表达式将使用索引。

如果索引是前锚定模式,则优化“like”使用索引比分析涉及字符串函数的任意表达式更容易进行优化。

答案 2 :(得分:7)

在SQL Server必须计算每行的结果的子句中使用函数调用会产生巨大影响。另一方面,like是内置语言功能,经过高度优化。

答案 3 :(得分:3)

如果在带索引的列上使用函数,则db不再使用索引(至少在Oracle中使用)
所以我猜你的示例字段'some_string_field'上有一个索引,它不会用于'LEFT'的查询

答案 4 :(得分:1)

为什么你说它们是相同的?他们可能会解决同样的问题,但他们的方法是不同的。至少看起来像......

使用LEFT的查询优化了测试,因为它已经知道了前缀的长度等等,因此在C / C ++ / ...程序中或没有索引时,使用LEFT实现某个LIKE的算法行为将是最快的。但与大多数非声明性语言相比,在SQL数据库上,为您完成了很多操作优化。例如,LIKE可能是通过首先查找%符号来实现的,如果注意到%是字符串中的最后一个char,则可以使用与使用LEFT相同的方式优化查询,但直接使用索引

所以,确实我认为你毕竟是,他们的方法可能完全相同。唯一的区别是db服务器可以使用LIKE在查询中使用索引,因为没有函数将列值转换为WHERE子句中未知的内容。

答案 5 :(得分:1)

这里发生的事情是RDBMS无法在LEFT()谓词上使用索引并且能够在LIKE上使用它,或者它只是做出错误的调用,其中更合适的访问方法

首先,对某些RDBMS来说,将一个函数应用于列可能会阻止使用基于索引的访问方法,但这不是一个普遍的事实,也没有任何逻辑上的原因需要它。基于索引的访问方法(例如Oracle的完整索引扫描或快速完整索引扫描)可能是有益的,但在某些情况下,RDBMS无法在基于函数的谓词的上下文中进行操作。

其次,优化者可能只是在估算不同可用访问方法的好处时弄错算法。假设系统可以执行基于索引的访问方法,它首先要估计与谓词匹配的行数,从表中的统计信息,列的统计信息,通过在分析时采样数据,或者使用启发式规则(例如“假设5%的行匹配”)。然后,它必须评估全表扫描或可用的基于索引的方法的相对成本。有时它会导致算术错误,有时统计数据会产生误导或不准确,有时启发式规则也不适合数据集。

关键是要注意一些问题:

  1. 您的RDBMS可以支持哪些操作?
  2. 什么是最合适的操作 你正在使用的案例?
  3. 系统的选择是否正确?
  4. 可以做些什么来让系统执行更有效的操作(例如,添加一个缺少的非空约束,更新统计数据等)?
  5. 根据我的经验,这不是一项微不足道的任务,通常最好留给专家。或者另一方面,只需将问题发布到Stackoverflow - 我们中的一些人发现这些东西很吸引人,狗帮助我们。

答案 6 :(得分:1)

正如@BradC所提到的,如果你有索引并希望利用它们,你就不应该在WHERE子句中使用函数。

如果您阅读标题为&#34的部分;当索引存在时,在WHERE子句中使用LIKE而不是LEFT()或SUBSTRING()&#34; from these SQL Performance Tips,还有更多例子。

如果您对采取这些问题感兴趣,它还会提示您在MCSE SQL Server 2012 exams遇到的问题。 : - )