在连接中使用like运算符时的膨胀基数估计

时间:2016-03-12 05:00:03

标签: oracle oracle11g query-optimization

使用' LIKE'通过连接,Oracle不使用索引,而当谓词作为常量字符串给出时就是这样。

我从一个简单的表TMP_RSQ_FEATURE开始,带有一个整数和字符串列。它有137,000行。它在FEATURE_NAME列上有一个名为TMP_R_FN的索引。

select dbms_metadata.get_ddl('TABLE', 'TMP_RSQ_FEATURE') from dual;

DBMS_METADATA.GET_DDL('TABLE','TMP_RSQ_FEATURE')
------------------------------------------------------------------

  CREATE TABLE TMP_RSQ_FEATURE
   (    "FEATURE_ID" NUMBER(8,0) NOT NULL ENABLE,
        "FEATURE_NAME" VARCHAR2(100) NOT NULL ENABLE
   ) SEGMENT CREATION IMMEDIATE

select dbms_metadata.get_ddl('INDEX', 'TMP_R_FN') from dual;

DBMS_METADATA.GET_DDL('INDEX','TMP_R_FN')
------------------------------------------------------------------

  CREATE INDEX TMP_R_FN ON TMP_RSQ_FEATURE ("FEATURE_NAME")
   ...

当我为LIKE谓词使用常量字符串时,查询是有效的,并且计划显示通过索引的访问:

select feature_id, feature_name 
  from tmp_rsq_feature f
  where f.feature_name like 'CD7%';

FEATURE_ID FEATURE_NAME
---------- ---------------------------------
   2442627 CD7
   2435077 CD70
   2448695 CD72
   2472766 CD74
   2491509 CD79A
   2442159 CD79B

6 rows selected.

Elapsed: 00:00:00.06

-----------------------------------------------------------------------------------------------
| Id  | Operation                   | Name            | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |                 |     1 |    17 |     4   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID| TMP_RSQ_FEATURE |     1 |    17 |     4   (0)| 00:00:01 |
|*  2 |   INDEX RANGE SCAN          | TMP_R_FN        |     1 |       |     2   (0)| 00:00:01 |
-----------------------------------------------------------------------------------------------

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

   2 - access("F"."FEATURE_NAME" LIKE 'CD7%')
       filter("F"."FEATURE_NAME" LIKE 'CD7%')

但是,当我尝试通过带有单行的参数表提供谓词时:

select * from spf_param;

VAL
-----------------------------------
CD7%

...并通过连接该字段的EXISTS条件提供谓词,查询速度慢10倍,并且不使用索引。

select feature_id, feature_name 
from tmp_rsq_feature f where exists
(select 0 from spf_param p where f.feature_name like p.val);

FEATURE_ID FEATURE_NAME
---------- ----------------------------------
   2491509 CD79A
   2448695 CD72
   2442159 CD79B
   2442627 CD7
   2472766 CD74
   2435077 CD70

6 rows selected.

Elapsed: 00:00:00.73

--------------------------------------------------------------------------------------
| Id  | Operation          | Name            | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |                 |     1 |    17 |   396K  (1)| 00:00:33 |
|*  1 |  FILTER            |                 |       |       |            |          |
|   2 |   TABLE ACCESS FULL| TMP_RSQ_FEATURE |   137K|  2284K|   120   (2)| 00:00:01 |
|*  3 |   TABLE ACCESS FULL| SPF_PARAM       |     1 |     5 |     3   (0)| 00:00:01 |
--------------------------------------------------------------------------------------

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

   1 - filter( EXISTS (SELECT 0 FROM "SPF_PARAM" "P" WHERE :B1 LIKE
              "P"."VAL"))
   3 - filter(:B1 LIKE "P"."VAL")

这似乎令人惊讶。首先,CBO知道SPF_PARAM只有一行。虽然它可能没有对该行的内容做任何假设,但非选择性的假设似乎表明它假设最坏,该列只是“#”;'%'。这似乎是一个过于保守的假设。是否有任何方法可以诱使CBO对SPF_PARAM的内容做出更强有力的假设?

0 个答案:

没有答案