在WHERE子句中使用DECODE参数将使用索引短路?

时间:2015-08-28 11:20:26

标签: oracle performance stored-procedures oracle11g

我有一个存储过程,其中包含多个必需参数和一个SELECT语句,其WHERE子句中有多个条件,如下所示:

SELECT *
FROM TABLE
WHERE column_1 = param_1
   AND column_2 = param_2
   AND column_3 = param_3;

此查询工作正常,它正确使用表上的索引。但是需求的变化意味着调整过程以便你可以传递更少的参数,所以可能只是前两个,但我们希望程序能够对存储过程进行最小的更改。

我提出的一个建议是使用DECODE函数来处理每个可能的NULL参数,如下所示:

SELECT *
FROM TABLE
WHERE column_1 = param_1
   AND column_2 = param_2
   AND column_3 = DECODE(param_3, null, column_3);

这样,我认为因为函数没有应用于表列,所以仍然会使用索引。我做了一些测试,查询仍然有效,即使在这种情况下也会使用索引。

但是我仍然与我们的架构师(没有其他解释)相矛盾,查询不会使用索引,因为我在WHERE子句中使用了一个函数。

我不确定我的更改是否足以证明始终使用索引,或者是否有其他情况我应该检查以及索引可能不< / em>因DECODE函数而被使用。

非常感谢任何帮助/建议/信息。

1 个答案:

答案 0 :(得分:5)

你是对的。测试并证明它。

<强>设置

SQL> CREATE TABLE t AS SELECT LEVEL id FROM dual CONNECT BY LEVEL <=10;

Table created.

SQL>
SQL> CREATE INDEX id_indx ON t(ID);

Index created.

测试用例

普通查询,没有任何功能:

SQL> set autot on explain
SQL>
SQL> SELECT * FROM t  WHERE ID = 5;

        ID
----------
         5


Execution Plan
----------------------------------------------------------
Plan hash value: 1629656632

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

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

   1 - access("ID"=5)

对值使用 DECODE 不在列):

SQL> SELECT * FROM t  WHERE ID = decode(5, NULL, 3, 5);

        ID
----------
         5


Execution Plan
----------------------------------------------------------
Plan hash value: 1629656632

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

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

   1 - access("ID"=5)

在值上使用 NVL 不在列):

SQL> SELECT * FROM t  WHERE ID = nvl(5, 3);

        ID
----------
         5


Execution Plan
----------------------------------------------------------
Plan hash value: 1629656632

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

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

   1 - access("ID"=5)

在所有这三种情况中,都使用索引

列上的DECODE:

SQL> SELECT * FROM t  WHERE decode(ID, NULL, 3, 5) = 5;

        ID
----------
         1
         2
         3
         4
         5
         6
         7
         8
         9
        10

10 rows selected.


Execution Plan
----------------------------------------------------------
Plan hash value: 1601196873

--------------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |     1 |     3 |     3   (0)| 00:00:01 |
|*  1 |  TABLE ACCESS FULL| T    |     1 |     3 |     3   (0)| 00:00:01 |
--------------------------------------------------------------------------

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

   1 - filter(DECODE(TO_CHAR("ID"),NULL,3,5)=5)

列上的NVL:

SQL> SELECT * FROM t  WHERE nvl(ID, 3) = 3;

        ID
----------
         3


Execution Plan
----------------------------------------------------------
Plan hash value: 1601196873

--------------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |     1 |     3 |     3   (0)| 00:00:01 |
|*  1 |  TABLE ACCESS FULL| T    |     1 |     3 |     3   (0)| 00:00:01 |
--------------------------------------------------------------------------

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

   1 - filter(NVL("ID",3)=3)

SQL>

正如预期的那样,当您在具有常规索引的列上应用函数时,不使用索引。您需要一个基于函数的索引。

所以,你是对的,当你没有在列上应用函数时,你不必担心索引的使用,而是在参数值上。