Oracle可选绑定变量

时间:2017-10-09 14:55:29

标签: oracle query-performance bind-variables

我有一个查询,从给定用户ID的表中选择用户。此参数是可选的。

这是查询:

SELECT * FROM USERS
WHERE (USER_ID = :USER_ID OR :USER_ID IS NULL)
ORDER BY USER_ID;

现在我执行查询找到一个用户,因此:USER_ID取得了英雄1:

SELECT * FROM USERS
WHERE (USER_ID = 1 OR 1 IS NULL)
ORDER BY USER_ID;

此查询需要5秒钟。

然后,我多次添加上一个查询OR :USER_ID IS NULL。这个例子比第一个花费更多的时间:

SELECT * FROM USERS
WHERE (USER_ID = 1 OR 1 IS NULL [OR 1 IS NULL]x100)
ORDER BY USER_ID;

此查询需要30秒。

执行计划在两个示例中相同:

---------------------------------------------------------------------------------------------------------------
| Id  | Operation                   | Name    | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     | Pstart| Pstop |
---------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |         |  3256K|   695M|       |   682K  (1)| 00:00:27 |       |       |
|   1 |  SORT ORDER BY              |         |  3256K|   695M|   877M|   682K  (1)| 00:00:27 |       |       |
|   2 |   PARTITION RANGE ALL       |         |  3256K|   695M|       |   534K  (1)| 00:00:21 |     1 |1048575|
|*  3 |    TABLE ACCESS STORAGE FULL| USERS |  3256K|   695M|       |   534K  (1)| 00:00:21 |     1 |1048575|

Oracle版本: Oracle Database 12c

为什么oracle不接受第一个声明,它总是正确的,并且停止评估其余声明?

1 个答案:

答案 0 :(得分:0)

您的问题是由FULL TABLE SCAN谓词触发的大型表上的OR

根据绑定变量的值,查询返回一行(如果绑定变量不是NULL)或者返回整个表。

对于一个绑定变量,您可以使用NVL 技巧

SELECT * FROM USERS
WHERE (USER_ID = nvl(:USER_ID, USER_ID))
ORDER BY USER_ID;

导致执行计划由两部分组成,涵盖两种情况:

BV为NULL - >全扫描

BV非空 - >索引ACCES

--------------------------------------------------------------------------------------------
| Id  | Operation                      | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT               |           |  8329 |  9313K|   941   (1)| 00:00:12 |
|   1 |  SORT ORDER BY                 |           |  8329 |  9313K|   941   (1)| 00:00:12 |
|   2 |   CONCATENATION                |           |       |       |            |          |
|*  3 |    FILTER                      |           |       |       |            |          |
|*  4 |     TABLE ACCESS FULL          | USERS     |  8247 |  9221K|   925   (1)| 00:00:12 |
|*  5 |    FILTER                      |           |       |       |            |          |
|   6 |     TABLE ACCESS BY INDEX ROWID| USERS     |    82 | 93890 |    15   (0)| 00:00:01 |
|*  7 |      INDEX RANGE SCAN          | USERS_IDX |  1110 |       |     1   (0)| 00:00:01 |
--------------------------------------------------------------------------------------------

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

   3 - filter(:USER_ID IS NULL)
   4 - filter("USER_ID" IS NOT NULL)
   5 - filter(:USER_ID IS NOT NULL)
   7 - access("USER_ID"=:USER_ID)

因此,如果BV被传递(非NULL),这将快速响应 AND 定义USER_ID上的索引。 这将导致整个表格的FULL TABLE SCAN(5秒) AND SORT(我的猜测是另外25秒),总回复时间为30秒。

请注意,如果您通过BV,则只执行FULL TABLE SCANSORT时间是可以忽略的,因为只返回一条记录(假设USER_ID为PK) - 这解释了响应的差异时间。