一尘不染

使用where子句中的函数的Oracle性能

sql

在一个存储过程(它的日期参数名为’paramDate’)中,我有一个类似这样的查询

select id, name
from customer
where period_aded = to_char(paramDate,'mm/yyyy')

Oracle将每一行的paramDate转换为字符串吗?

我确定Oracle不会,但是有人告诉我Oracle会。实际上,我认为如果函数的参数是约束条件(查询中没有固定值或计算值),结果应该始终相同,这就是Oracle应该只执行一次此转换的原因。然后我意识到有时我会在多个函数中执行DML语句,这可能会导致结果值发生变化,即使每行的值都没有变化。

这应该意味着我应该在将这些值添加到查询之前进行转换。

无论如何,也许一次(内置)众所周知的“已知函数”都会被评估一次,甚至我的函数也会被评估一次。

反正…

oracle将执行一次to_char还是Oracle将对每一行执行一次?

谢谢你的回答


阅读 122

收藏
2021-05-30

共1个答案

一尘不染

我认为通常不是这种情况,因为它会阻止使用索引。

至少对于内置功能,Oracle应该能够弄清楚它只能评估一次。(有关用户定义的功能,请参见下文)。

在这种情况下,正在使用索引(并且并非对每一行都评估该函数):

SQL> select id from tbl_table where id > to_char(sysdate, 'YYYY');

--------------------------------------------------------------------------------
| Id  | Operation        | Name        | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------
|   0 | SELECT STATEMENT |             |    35 |   140 |     1   (0)| 00:00:01 |
|*  1 |  INDEX RANGE SCAN| SYS_C004274 |    35 |   140 |     1   (0)| 00:00:01 |
--------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

1 - access("ID">TO_NUMBER(TO_CHAR(SYSDATE@!,'YYYY')))

有关用户定义的功能,请查看本文。它提到了两种确保函数仅被调用一次的方法:

  1. 从Oracle 10.2开始,您可以将函数定义为DETERMINISTIC。

  2. 在较旧的版本上,您可以重新命名为使用“标量子查询缓存”:

从雇员薪水中选择COUNT(*)=(从DUAL中选择getValue(1));

2021-05-30