Sql 优化Oracle查询-where子句中的函数

Sql 优化Oracle查询-where子句中的函数,sql,oracle,indexing,Sql,Oracle,Indexing,我一次又一次地被告知优化查询的最佳方法是删除where子句中的函数。函数导致全表扫描。因此,我的问题是,考虑到这三个查询,为什么在where子句附件C中具有函数的查询执行得最好——速度是前者的两倍以上 附件A-中的文本大写,因此where子句中没有函数,但仍将where子句放在select中 With Code As ( Select owner,name,Upper(text) As text,line From all_source ) select * from Code Where te

我一次又一次地被告知优化查询的最佳方法是删除where子句中的函数。函数导致全表扫描。因此,我的问题是,考虑到这三个查询,为什么在where子句附件C中具有函数的查询执行得最好——速度是前者的两倍以上

附件A-中的文本大写,因此where子句中没有函数,但仍将where子句放在select中

With Code As (
Select owner,name,Upper(text) As text,line From all_source
)
select * from Code
Where text Like '%UPPER(%'
And owner='COMMISSIONS'
附件B-文本中的大写字母,并尽可能进行过滤

With Code As (
Select owner,name,Upper(text) As text,line From all_source
Where owner='COMMISSIONS'
)
select * from Code
Where text Like '%UPPER(%'
附件C-不带with子句和where子句中的函数

select * from all_source
Where upper(text) Like '%UPPER(%'
And owner='COMMISSIONS'
TL;DR-由于缓存,您的第三个查询可能运行得最快。就性能而言,它既不比其他两个好也不比其他两个差。但它是最简单的,也是你应该使用的

为什么带有where子句附件C中的函数的函数执行得最好

在Oracle的优化器处理完这三个查询之后,它们基本上是相同的。如果第三个运行得更快,可能是因为在ALL_源代码视图下的表中有索引,因为您指定了owner='COMMISSIONS'。使用索引访问的索引块和表块可以存储在块缓冲区缓存中。您的第三个查询得益于前两个已经读取并缓存了它所需的一些数据。证据再次运行第一个查询

但更重要的是:从WHERE子句中删除函数并不是描述常规通知的确切方式

传统的建议旨在帮助新的Oracle开发人员意识到索引的局限性

拿出你最喜欢的技术参考资料,转到后面的索引。使用它查找以so开头的每个主题的主题和页码。索引非常有用,对吗?现在使用索引查找以r结尾的主题和页码,类似的Oracle函数是substrtopic,-1='r'。索引不再有用了。Oracle索引也受到同样的限制

现在,您的技术参考的作者可以在后面创建第二个索引,根据他们的最后一封信组织所有主题。如果他们这样做的话,这个指数对于我上面给你的第二个练习会非常有用。类似地,Oracle可以创建基于函数的索引来回答基于该函数的查询,例如substrtopic,-1

但是,在没有预先存在的基于函数的索引的情况下,对列的函数进行过滤的查询不会受益于该列的索引。这是一个推广,也有例外,比如覆盖索引,但这是一个很好的推广

但是,这些都不是关于WHERE子句中的函数的。所有这三个查询都会阻止Oracle对文本使用索引。通过使用view或WITH子句来执行函数来避免WHERE子句中的函数并不能使您绕过Oracle索引的限制


旁白:您在文本列上使用LIKE运算符这一事实是索引没有帮助的另一个重要原因-请参阅Oracle文本功能以获得更好的选项,如CONTAINS运算符。

我猜您在owner上有一个索引,这三个运算符的性能非常相似。为了正确回答您的问题,我们需要要知道所有源的表都有哪些索引。如果没有这些信息,我们几乎无法猜测。例如,如果您创建以下索引,您的查询3可能会更快:在所有源所有者uppertext;上创建索引ix1;。这样做,看看它的表现。非常有帮助。这里是对Like vs Contains的引用。