是什么使SQL语句可存储?


252

根据定义(至少从我所看到的意义上),可精简意味着查询能够使查询引擎优化查询所使用的执行计划。我尝试查找答案,但是在主题上似乎没有很多。所以问题是,什么使SQL查询可持久化?任何文件将不胜感激。

供参考:SARGable


58
+1为“可续”。这就是我今天的话。:-p
BFree

1
我还可以补充亚当的答案,即在大多数情况下,每个数据库引擎都需要大量的信息。
Hoagie

30
SARG =搜索参数。有趣的是:德语中的“ SARG”意为“棺材”,所以当人们谈论可食用的东西时,我总是要微笑-可以放在棺材里吗?:-)
marc_s

可持久性取决于您的环境。MySQL的记录在这里:dev.mysql.com/doc/refman/5.0/en/mysql-indexes.html
Frank Farmer 2010年

使用自由文本字段而不是“查找表”也违反了使查询可存储的精神。用户输入自由文本(例如镇名)时拼写错误,而查找表则迫使用户选择拼写正确的条目。值得稍微麻烦一点,因为它可以正确地索引,而不是在谓词中使用LIKE'%...%'。
反向工程师

Answers:


256

使查询不可更改的最常见的事情是在where子句的函数内部包括一个字段:

SELECT ... FROM ...
WHERE Year(myDate) = 2008

SQL优化器无法在myDate上使用索引,即使存在索引也是如此。从字面上看,它必须为表的每一行评估此功能。更好地使用:

WHERE myDate >= '01-01-2008' AND myDate < '01-01-2009'

其他一些例子:

Bad: Select ... WHERE isNull(FullName,'Ed Jones') = '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()) 

7
内含函数 GROUP BY会导致查询不可修改吗?
Mike Bailey 2012年

1
一些数据库引擎(Oracle,PostgreSQL)支持表达式索引,不知道吗?
克雷格2014年

3
将一个更好的版本WHERE ((FullName = 'Ed Jones') OR (FullName IS NULL))SELECT... FROM ... WHERE FullName = 'Ed Jones' UNION SELECT...FROM...WHERE FullName IS NULL?曾经有一个优化专家告诉我,在where子句中使用OR可以取消查询的参数..?
High Plains Grifter,2015年

2
@HighPlainsGrifter,您应该在该查询上使用UNION ALL-union具有隐式的distinct,这使查询的成本大大高于必须互斥的数据集时的成本
Devin Lamothe

1
@BradC在MSSQL 2016中,Select ... WHERE isNull(FullName,'Ed Jones') = 'Ed Jones'和之间没有执行计划差异Select ... WHERE ((FullName = 'Ed Jones') OR (FullName IS NULL))。他们都使用FullName上的索引并进行索引查找。
CEGRD

79

不要这样做:

WHERE Field LIKE '%blah%'

这会导致表/索引扫描,因为LIKE值以通配符开头。

不要这样做:

WHERE FUNCTION(Field) = 'BLAH'

这将导致表/索引扫描。

数据库服务器将不得不针对表中的每一行评估FUNCTION(),然后将其与“ BLAH”进行比较。

如果可能,请反向执行:

WHERE Field = INVERSE_FUNCTION('BLAH')

这将对参数运行一次INVERSE_FUNCTION(),并且仍然允许使用索引。


5
您关于翻转函数的建议实际上仅在函数往返数据时才有效(这意味着f(f(n))= n)。
亚当·罗宾逊

5
真正。我考虑过添加INVERSE_FUNCTION,但不想造成混淆。我会改变它。
海滩

9

在这个答案中,我假设数据库具有足够的覆盖索引。关于这个话题有足够的疑问。

很多时候,查询的可保存性由相关索引的临界点确定。引爆点定义了在将一个表或结果集连接到另一个表或结果集时查找和扫描索引之间的差异。当然,一次查找比扫描整个表要快得多,但是当您必须查找很多行时,扫描可能更有意义。

因此,当优化程序期望一个表的结果行数小于下一个表的可能索引的临界点时,SQL语句更易处理。

您可以在此处找到详细的帖子和示例。


4

对于被认为是可操作的操作,仅使用现有索引是不够的。在上面的示例中,在where子句中对索引列添加函数调用,仍然很有可能会利用已定义的索引。它也将“扫描”该列(索引)中的所有值,然后消除那些与提供的过滤器值不匹配的值。对于行数很高的表,它仍然不够高效。真正定义可保存性的是使用二进制搜索方法遍历b树索引的查询能力,该方法依赖于排序项目数组的半集消除。在SQL中,它将在执行计划上显示为“索引查找”。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.