如何 select oracle 上的可选参数(减少 oracle 的执行时间)?
How to select optional parameters on oracle (Decrease execution time of oracle)?
我必须减少它的执行时间。当我刚插入“:i_member_name”时,这条语句处理浪费了大约30分钟,其他都是空的。
SELECT
A.MEMBER_NUM, A.MEMBER_NAME, B.MEMBER_INFO FROM REG_MEMBER A, MEMBER_DETAIL B
WHERE A.MEMBER_ID = B.MEMBER_ID
AND (LOWER(A.MEMBER_NAME) LIKE LOWER(:i_member_name || '%'))
AND (LOWER(B.MEMBER_INFO) LIKE LOWER(:i_member_info || '%'))
AND (A.MEMBER_NUM LIKE :i_member_num || '%')
AND (LOWER(B.MEMBER_ADD) LIKE LOWER('%' || :i_member_add || '%'))
如果我这样执行,没关系,只是浪费了 30 秒。
SELECT
A.MEMBER_NUM, A.MEMBER_NAME, B.MEMBER_INFO FROM REG_MEMBER A, MEMBER_DETAIL B
WHERE A.MEMBER_ID = B.MEMBER_ID
AND (LOWER(A.MEMBER_NAME) LIKE LOWER(:i_member_name || '%'))
--AND (LOWER(B.MEMBER_INFO) LIKE LOWER(:i_member_info || '%'))
--AND (A.MEMBER_NUM LIKE :i_member_num || '%')
--AND (LOWER(B.MEMBER_ADD) LIKE LOWER('%' || :i_member_add || '%'))
所以我有一个问题:如何检查参数是否为空然后不要读取更多的执行时间。像这样
SELECT A.MEMBER_NUM, A.MEMBER_NAME, B.MEMBER_INFO FROM REG_MEMBER A, MEMBER_DETAIL B
WHERE
(LOWER(A.MEMBER_NAME) LIKE LOWER(:i_member_name || '%'))
and case when :i_member_num is null then return
else (A.MEMBER_NUM LIKE :i_member_num || '%')
end
检查 SQL 中可选参数的最快方法通常是使用 NVL
。
Oracle 通常可以将 NVL
表达式扩展为两个独立的子计划。 FILTER
操作将在 运行 时间运行以仅选择计划的一部分。例如,它可以使用 INDEX RANGE SCAN
和绑定值,如 'Smith%'
是可搜索的;它可以使用 TABLE ACCESS FULL
和绑定值,如 NULL
不可搜索。
下面是一个使用您问题中的一小部分对象的示例:
--Create table and index.
create table reg_member(member_num number, member_name varchar2(100));
create index reg_member_idx on reg_member(lower(member_name));
--Generate explain plan.
EXPLAIN PLAN FOR
SELECT
A.MEMBER_NUM, A.MEMBER_NAME
FROM REG_MEMBER A
WHERE NVL(:i_member_name, LOWER(A.MEMBER_NAME)) = LOWER(A.MEMBER_NAME);
--Show explain plan.
select * from table(dbms_xplan.display);
Plan hash value: 3501926772
----------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 2 | 130 | 3 (0)| 00:00:01 |
| 1 | VIEW | VW_ORE_377C5901 | 2 | 130 | 3 (0)| 00:00:01 |
| 2 | UNION-ALL | | | | | |
|* 3 | FILTER | | | | | |
| 4 | TABLE ACCESS BY INDEX ROWID BATCHED| REG_MEMBER | 1 | 117 | 1 (0)| 00:00:01 |
|* 5 | INDEX RANGE SCAN | REG_MEMBER_IDX | 1 | | 1 (0)| 00:00:01 |
|* 6 | FILTER | | | | | |
|* 7 | TABLE ACCESS FULL | REG_MEMBER | 1 | 117 | 2 (0)| 00:00:01 |
----------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - filter(:I_MEMBER_NAME IS NOT NULL)
5 - access(LOWER("MEMBER_NAME")=:I_MEMBER_NAME)
6 - filter(:I_MEMBER_NAME IS NULL)
7 - filter(LOWER("MEMBER_NAME") IS NOT NULL)
Note
-----
- dynamic statistics used: dynamic sampling (level=2)
NVL
FILTER
操作在某些情况下效果很好。但很难说它是否能解决您的具体问题,因为变量太多:对象是否具有正确的索引,所有谓词如何协同工作等等。但是 NVL
是一个很好的起点。
我必须减少它的执行时间。当我刚插入“:i_member_name”时,这条语句处理浪费了大约30分钟,其他都是空的。
SELECT
A.MEMBER_NUM, A.MEMBER_NAME, B.MEMBER_INFO FROM REG_MEMBER A, MEMBER_DETAIL B
WHERE A.MEMBER_ID = B.MEMBER_ID
AND (LOWER(A.MEMBER_NAME) LIKE LOWER(:i_member_name || '%'))
AND (LOWER(B.MEMBER_INFO) LIKE LOWER(:i_member_info || '%'))
AND (A.MEMBER_NUM LIKE :i_member_num || '%')
AND (LOWER(B.MEMBER_ADD) LIKE LOWER('%' || :i_member_add || '%'))
如果我这样执行,没关系,只是浪费了 30 秒。
SELECT
A.MEMBER_NUM, A.MEMBER_NAME, B.MEMBER_INFO FROM REG_MEMBER A, MEMBER_DETAIL B
WHERE A.MEMBER_ID = B.MEMBER_ID
AND (LOWER(A.MEMBER_NAME) LIKE LOWER(:i_member_name || '%'))
--AND (LOWER(B.MEMBER_INFO) LIKE LOWER(:i_member_info || '%'))
--AND (A.MEMBER_NUM LIKE :i_member_num || '%')
--AND (LOWER(B.MEMBER_ADD) LIKE LOWER('%' || :i_member_add || '%'))
所以我有一个问题:如何检查参数是否为空然后不要读取更多的执行时间。像这样
SELECT A.MEMBER_NUM, A.MEMBER_NAME, B.MEMBER_INFO FROM REG_MEMBER A, MEMBER_DETAIL B
WHERE
(LOWER(A.MEMBER_NAME) LIKE LOWER(:i_member_name || '%'))
and case when :i_member_num is null then return
else (A.MEMBER_NUM LIKE :i_member_num || '%')
end
检查 SQL 中可选参数的最快方法通常是使用 NVL
。
Oracle 通常可以将 NVL
表达式扩展为两个独立的子计划。 FILTER
操作将在 运行 时间运行以仅选择计划的一部分。例如,它可以使用 INDEX RANGE SCAN
和绑定值,如 'Smith%'
是可搜索的;它可以使用 TABLE ACCESS FULL
和绑定值,如 NULL
不可搜索。
下面是一个使用您问题中的一小部分对象的示例:
--Create table and index.
create table reg_member(member_num number, member_name varchar2(100));
create index reg_member_idx on reg_member(lower(member_name));
--Generate explain plan.
EXPLAIN PLAN FOR
SELECT
A.MEMBER_NUM, A.MEMBER_NAME
FROM REG_MEMBER A
WHERE NVL(:i_member_name, LOWER(A.MEMBER_NAME)) = LOWER(A.MEMBER_NAME);
--Show explain plan.
select * from table(dbms_xplan.display);
Plan hash value: 3501926772
----------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 2 | 130 | 3 (0)| 00:00:01 |
| 1 | VIEW | VW_ORE_377C5901 | 2 | 130 | 3 (0)| 00:00:01 |
| 2 | UNION-ALL | | | | | |
|* 3 | FILTER | | | | | |
| 4 | TABLE ACCESS BY INDEX ROWID BATCHED| REG_MEMBER | 1 | 117 | 1 (0)| 00:00:01 |
|* 5 | INDEX RANGE SCAN | REG_MEMBER_IDX | 1 | | 1 (0)| 00:00:01 |
|* 6 | FILTER | | | | | |
|* 7 | TABLE ACCESS FULL | REG_MEMBER | 1 | 117 | 2 (0)| 00:00:01 |
----------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - filter(:I_MEMBER_NAME IS NOT NULL)
5 - access(LOWER("MEMBER_NAME")=:I_MEMBER_NAME)
6 - filter(:I_MEMBER_NAME IS NULL)
7 - filter(LOWER("MEMBER_NAME") IS NOT NULL)
Note
-----
- dynamic statistics used: dynamic sampling (level=2)
NVL
FILTER
操作在某些情况下效果很好。但很难说它是否能解决您的具体问题,因为变量太多:对象是否具有正确的索引,所有谓词如何协同工作等等。但是 NVL
是一个很好的起点。