Symptom: SYS_OP_C2C Causing FULL Table Scan Instead of Index Range Scan


SYS_OP_C2C is the implicit function that is used to convert the column between NCHAR and CHAR;

Cause:
When bind variable "string" is using a different datatype (e.g. NVARCHAR2) to the column (e.g. VARCHAR2) that is being queried,
index range scan is ignored.

Solution:
Create a function base index on the column using the following syntax:

create index <index_name> on <table_name> (SYS_OP_C2C(<column>));

Here's the test:

alter system flush shared_pool;
alter system flush shared_pool;
alter system flush buffer_cache;
alter system flush buffer_cache;


create table test_char
(c1 varchar2(10));

begin
for i in 1 .. 100000 loop
insert /*+APPEND*/ into test_char(c1) values('中'||i);
end loop;
commit;
end;
/

create index idx_test_char on test_char(c1) ;

 

var search_text nvarchar2(10)
exec :search_text:='中100';
select * from test_char where c1 = '中100';

C1
--------------------
中100

select * from test_char where c1 = :search_text;
C1
--------------------
中100


col sql_id format a20
col sql_text format a50
select sql_id,sql_text from v$sql where sql_text like '%test_char%';
>>
SQL_ID SQL_TEXT
-------------------- --------------------------------------------------
42tbgppd765j2 select * from test_char where c1 = :"SYS_B_0"
2tbafah8m78x0 select * from test_char where c1 = :search_text

 

select * from table(dbms_xplan.display_cursor('42tbgppd765j2',null,'ADVANCED'));
PLAN_TABLE_OUTPUT
-------------------------------------------------------------------------------------------------
SQL_ID 42tbgppd765j2, child number 0
-------------------------------------
select * from test_char where c1 = :"SYS_B_0"

Plan hash value: 4273954991

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

Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------

1 - SEL$1 / TEST_CHAR@SEL$1

Outline Data
-------------

/*+
BEGIN_OUTLINE_DATA
IGNORE_OPTIM_EMBEDDED_HINTS
OPTIMIZER_FEATURES_ENABLE('11.2.0.3')
DB_VERSION('11.2.0.3')
ALL_ROWS
OUTLINE_LEAF(@"SEL$1")
INDEX(@"SEL$1" "TEST_CHAR"@"SEL$1" ("TEST_CHAR"."C1"))
END_OUTLINE_DATA
*/

Peeked Binds (identified by position):
--------------------------------------

1 - :SYS_B_0 (VARCHAR2(30), CSID=873): '中100'

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

1 - access("C1"=:SYS_B_0)

Column Projection Information (identified by operation id):
-----------------------------------------------------------

1 - "C1"[VARCHAR2,10]

Note
-----
- dynamic sampling used for this statement (level=2)


已選取 51 個資料列.

 

select * from table(dbms_xplan.display_cursor('2tbafah8m78x0',null,'ADVANCED'));

PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------
SQL_ID 2tbafah8m78x0, child number 0
-------------------------------------
select * from test_char where c1 = :search_text

Plan hash value: 718057891

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

Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------

1 - SEL$1 / TEST_CHAR@SEL$1

Outline Data
-------------

/*+
BEGIN_OUTLINE_DATA
IGNORE_OPTIM_EMBEDDED_HINTS
OPTIMIZER_FEATURES_ENABLE('11.2.0.3')
DB_VERSION('11.2.0.3')
ALL_ROWS
OUTLINE_LEAF(@"SEL$1")
FULL(@"SEL$1" "TEST_CHAR"@"SEL$1")
END_OUTLINE_DATA
*/

Peeked Binds (identified by position):
--------------------------------------

1 - :SEARCH_TEXT (NVARCHAR2(30), CSID=2000): '中100'

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

1 - filter(SYS_OP_C2C("C1")=:SEARCH_TEXT)

Column Projection Information (identified by operation id):
-----------------------------------------------------------

1 - "C1"[VARCHAR2,10]

Note
-----
- dynamic sampling used for this statement (level=2)


已選取 51 個資料列.

 

create index idx2_test_char on test_char(SYS_OP_C2C("C1")) ;


var search_text nvarchar2(10)
exec :search_text:='中100';
select * from test_char where c1 = '中100';

C1
--------------------
中100

select * from test_char where c1 = :search_text;

C1
--------------------
中100


col sql_id format a20
col sql_text format a50
select sql_id,sql_text from v$sql where sql_text like '%test_char%';

SQL_ID SQL_TEXT
-------------------- --------------------------------------------------
42tbgppd765j2 select * from test_char where c1 = :"SYS_B_0"
2tbafah8m78x0 select * from test_char where c1 = :search_text


select * from table(dbms_xplan.display_cursor('42tbgppd765j2'));

PLAN_TABLE_OUTPUT
-----------------------------------------------------------------------------------------
SQL_ID 42tbgppd765j2, child number 0
-------------------------------------
select * from test_char where c1 = :"SYS_B_0"

Plan hash value: 4273954991

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

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

1 - access("C1"=:SYS_B_0)

Note
-----
- dynamic sampling used for this statement (level=2)


已選取 22 個資料列.


select * from table(dbms_xplan.display_cursor('2tbafah8m78x0'));

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------
SQL_ID 2tbafah8m78x0, child number 0
-------------------------------------
select * from test_char where c1 = :search_text

Plan hash value: 3111331547

----------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 67 (100)| |
| 1 | TABLE ACCESS BY INDEX ROWID| TEST_CHAR | 905 | 17195 | 67 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | IDX2_TEST_CHAR | 362 | | 1 (0)| 00:00:01 |
----------------------------------------------------------------------------------------------

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

2 - access("TEST_CHAR"."SYS_NC00002$"=:SEARCH_TEXT)

Note
-----
- dynamic sampling used for this statement (level=2)


已選取 23 個資料列.


[reference]
My Oracle Support: SYS_OP_C2C Causing Full Table/Index Scans [Doc ID 732666.1]

arrow
arrow
    全站熱搜
    創作者介紹
    創作者 DanBrother 的頭像
    DanBrother

    DanBrother的部落格

    DanBrother 發表在 痞客邦 留言(0) 人氣()