【问题标题】:How to select optional parameters on oracle (Decrease execution time of oracle)?如何在oracle上选择可选参数(减少oracle的执行时间)?
【发布时间】:2017-06-08 00:55:01
【问题描述】:

我必须减少它的执行时间。当我刚刚插入“: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

【问题讨论】:

  • 使用布尔逻辑。将AND (LOWER(B.MEMBER_INFO) LIKE LOWER(:i_member_info || '%')) 更改为(AND (LOWER(B.MEMBER_INFO) LIKE LOWER(:i_member_info || '%')) OR :i_member_info IS NULL)。但这可能没有什么不同 - 您需要使用查询计划来检查
  • 也许还有另一种方法 - 在lower(member_name) 等上创建索引?由于您必须在lower() 内进行包装,因此member_name 本身的索引将无济于事。
  • 你能详细说明一下吗?

标签: sql oracle select parameters case-when


【解决方案1】:

在 SQL 中检查可选参数的最快方法通常是使用NVL

Oracle 通常可以将NVL 表达式扩展为两个单独的子计划。 FILTER 操作将在运行时仅选择计划的一部分。例如,它可以使用带有绑定值的INDEX RANGE SCAN,如'Smith%',它是sargable;它可以使用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_info, :i_member_add, :i_member_num / 我需要为每一个创建索引吗?
  • @user2801618 您只需要使用EXPLAIN PLAN查看计划。由于您的查询可能使用列的任何组合,我认为索引所有相关列和表达式是有意义的。
  • '在 reg_member(lower(member_name)) 上创建索引 reg_member_idx;在 reg_member(lower(i_member_num )) 上创建索引 reg_member_idx2;在 reg_member(lower(i_member_add)) 上创建索引 reg_member_idx3;'像这样?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-11-05
  • 2013-10-31
  • 1970-01-01
  • 2021-12-28
  • 1970-01-01
  • 1970-01-01
  • 2013-11-18
相关资源
最近更新 更多