FIRST_ROWS优化模式语言排序模糊匹配问题
2012-03-09 00:00
330 查看
标题比较长,不过只有这样才能把问题描述清楚。
问题详细描述为,在FIRST_ROWS优化模式下,将会话排序和比较方式设置为语义模式,即忽略大小写模式,对字段进行LIKE模糊查询,可能导致错误的结果。
关于大小写不敏感的查询的详细描述,可以参考:http://yangtingkun.itpub.net/post/468/460324
下面直接看问题的现象:
SQL> CREATE TABLE T1 (ID NUMBER PRIMARY KEY, NAME VARCHAR2(30));
表已创建。
SQL> CREATE INDEX IND_T1_NAME ON T1(NAME);
索引已创建。
SQL> INSERT INTO T1 SELECT ROWNUM, CHR(64 + ROWNUM)
2 FROM ALL_OBJECTS WHERE ROWNUM <= 26;
已创建26行。
SQL> COMMIT;
提交完成。
SQL> ALTER SESSION SET NLS_COMP = LINGUISTIC;
会话已更改。
SQL> ALTER SESSION SET NLS_SORT = BINARY_CI;
会话已更改。
SQL> SELECT * FROM T1 WHERE NAME LIKE 'a%';
ID NAME
---------- ------------------------------
1 A
SQL> SELECT /*+ FIRST_ROWS */ * FROM T1 WHERE NAME LIKE 'a%';
未选定行
只要修改上面提到的关键点中的任意一个,就不会产生这个错误的现象:
SQL> SELECT /*+ ALL_ROWS */ * FROM T1 WHERE NAME LIKE 'a%';
ID NAME
---------- ------------------------------
1 A
SQL> SELECT /*+ FIRST_ROWS */ * FROM T1 WHERE NAME = 'a';
ID NAME
---------- ------------------------------
1 A
SQL> ALTER SESSION SET NLS_SORT = BINARY;
会话已更改。
SQL> ALTER SESSION SET NLS_COMP = BINARY;
会话已更改。
SQL> SELECT /*+ FIRST_ROWS */ * FROM T1 WHERE NAME LIKE 'A%';
ID NAME
---------- ------------------------------
1 A
SQL> ALTER SESSION SET NLS_COMP = LINGUISTIC;
会话已更改。
SQL> ALTER SESSION SET NLS_SORT = BINARY_CI;
会话已更改。
SQL> SELECT /*+ FIRST_ROWS */ * FROM T1 WHERE NAME LIKE 'A%';
ID NAME
---------- ------------------------------
1 A
SQL> SELECT /*+ FIRST_ROWS */ * FROM T1 WHERE NAME LIKE 'a';
未选定行
通过上面的几个查询可以看到,问题和FIRST_ROWS,LIKE操作以及基于语义的排序直接相关,下面看看Oracle在异常情况下采用了何种执行计划:
SQL> SET AUTOT ON EXP
SQL> SELECT /*+ FIRST_ROWS */ * FROM T1 WHERE NAME LIKE 'a';
未选定行
执行计划
----------------------------------------------------------
Plan hash value: 3350237141
-------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 30 | 35 (0)| 00:00:01 |
|* 1 | VIEW | index$_join$_001 | 1 | 30 | 35 (0)| 00:00:01 |
|* 2 | HASH JOIN | | | | | |
|* 3 | INDEX RANGE SCAN | IND_T1_NAME | 1 | 30 | 3 (34)| 00:00:01 |
| 4 | INDEX FAST FULL SCAN| SYS_C006622 | 1 | 30 | 33 (0)| 00:00:01 |
-------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("NAME" LIKE 'a')
2 - access(ROWID=ROWID)
3 - access("NAME" LIKE 'a')
Note
-----
- dynamic sampling used for this statement
由于索引中并不包含语义查询的结果,因此Oracle这里必须访问表才能得到最终的结果,因此这个执行计划是错误的:
SQL> SELECT * FROM T1 WHERE NAME = 'a';
ID NAME
---------- ------------------------------
1 A
执行计划
----------------------------------------------------------
Plan hash value: 3617692013
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 30 | 3 (0)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| T1 | 1 | 30 | 3 (0)| 00:00:01 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(NLSSORT("NAME",'nls_sort=''BINARY_CI''')=HEXTORAW('6100')
)
Note
-----
- dynamic sampling used for this statement
SQL> SELECT /*+ INDEX(T1) */ * FROM T1 WHERE NAME = 'a';
ID NAME
---------- ------------------------------
1 A
执行计划
----------------------------------------------------------
Plan hash value: 159298173
-------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 30 | 827 (1)| 00:00:10 |
|* 1 | TABLE ACCESS BY INDEX ROWID| T1 | 1 | 30 | 827 (1)| 00:00:10 |
| 2 | INDEX FULL SCAN | SYS_C006622 | 26 | | 26 (0)| 00:00:01 |
-------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(NLSSORT("NAME",'nls_sort=''BINARY_CI''')=HEXTORAW('6100') )
Note
-----
- dynamic sampling used for this statement
上面的两个执行计划已经说明了问题的关键,Oracle对于语义的排序无法通过索引获取,必须要访问表或者相应的函数索引,详细描述可以参考文章开头部分给出的链接。
而采用了FIRST_ROWS优化模式后,当操作为LIKE时,Oracle优化器选择了错误的执行计划进行了优化,采用索引的范围扫描代替了表,从而引发了错误:
SQL> SELECT /*+ INDEX_JOIN(T1 IND_T1_NAME SYS_C006622) */ *
2 FROM T1
3 WHERE NAME LIKE 'a';
未选定行
执行计划
----------------------------------------------------------
Plan hash value: 3350237141
-------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 30 | 35 (0)| 00:00:01 |
|* 1 | VIEW | index$_join$_001 | 1 | 30 | 35 (0)| 00:00:01 |
|* 2 | HASH JOIN | | | | | |
|* 3 | INDEX RANGE SCAN | IND_T1_NAME | 1 | 30 | 3 (34)| 00:00:01 |
| 4 | INDEX FAST FULL SCAN| SYS_C006622 | 1 | 30 | 33 (0)| 00:00:01 |
-------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("NAME" LIKE 'a')
2 - access(ROWID=ROWID)
3 - access("NAME" LIKE 'a')
Note
-----
- dynamic sampling used for this statement
现在没有使用FIRST_ROWS,而采用HINT也达到了相同的效果。而解决这个问题的方法就是通过HINT来避免索引范围扫描的发生。
SQL> ALTER SESSION SET OPTIMIZER_MODE = FIRST_ROWS;
会话已更改。
SQL> SELECT * FROM T1 WHERE NAME LIKE 'a';
未选定行
执行计划
----------------------------------------------------------
Plan hash value: 3350237141
-------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 30 | 35 (0)| 00:00:01 |
|* 1 | VIEW | index$_join$_001 | 1 | 30 | 35 (0)| 00:00:01 |
|* 2 | HASH JOIN | | | | | |
|* 3 | INDEX RANGE SCAN | IND_T1_NAME | 1 | 30 | 3 (34)| 00:00:01 |
| 4 | INDEX FAST FULL SCAN| SYS_C006622 | 1 | 30 | 33 (0)| 00:00:01 |
-------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("NAME" LIKE 'a')
2 - access(ROWID=ROWID)
3 - access("NAME" LIKE 'a')
Note
-----
- dynamic sampling used for this statement
SQL> SELECT /*+ FULL(T1) */ * FROM T1 WHERE NAME LIKE 'a';
ID NAME
---------- ------------------------------
1 A
执行计划
----------------------------------------------------------
Plan hash value: 3617692013
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 30 | 3 (0)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| T1 | 1 | 30 | 3 (0)| 00:00:01 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("NAME" LIKE 'a')
Note
-----
- dynamic sampling used for this statement
SQL> SELECT /*+ NO_INDEX(T1) */ * FROM T1 WHERE NAME LIKE 'a';
ID NAME
---------- ------------------------------
1 A
执行计划
----------------------------------------------------------
Plan hash value: 3617692013
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 30 | 3 (0)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| T1 | 1 | 30 | 3 (0)| 00:00:01 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("NAME" LIKE 'a')
Note
-----
- dynamic sampling used for this statement
查询metalink,Oracle在Doc ID: Note:5252496.8明确说明了这个bug,这个bug会在Oracle10.2.0.4和11.1.0.6中被Fixed。
$(document).ready(function(){dp.SyntaxHighlighter.HighlightAll('code');});
原文链接:
http://blog.csdn.net/newhappy2008/article/details/2316044
问题详细描述为,在FIRST_ROWS优化模式下,将会话排序和比较方式设置为语义模式,即忽略大小写模式,对字段进行LIKE模糊查询,可能导致错误的结果。
关于大小写不敏感的查询的详细描述,可以参考:http://yangtingkun.itpub.net/post/468/460324
下面直接看问题的现象:
SQL> CREATE TABLE T1 (ID NUMBER PRIMARY KEY, NAME VARCHAR2(30));
表已创建。
SQL> CREATE INDEX IND_T1_NAME ON T1(NAME);
索引已创建。
SQL> INSERT INTO T1 SELECT ROWNUM, CHR(64 + ROWNUM)
2 FROM ALL_OBJECTS WHERE ROWNUM <= 26;
已创建26行。
SQL> COMMIT;
提交完成。
SQL> ALTER SESSION SET NLS_COMP = LINGUISTIC;
会话已更改。
SQL> ALTER SESSION SET NLS_SORT = BINARY_CI;
会话已更改。
SQL> SELECT * FROM T1 WHERE NAME LIKE 'a%';
ID NAME
---------- ------------------------------
1 A
SQL> SELECT /*+ FIRST_ROWS */ * FROM T1 WHERE NAME LIKE 'a%';
未选定行
只要修改上面提到的关键点中的任意一个,就不会产生这个错误的现象:
SQL> SELECT /*+ ALL_ROWS */ * FROM T1 WHERE NAME LIKE 'a%';
ID NAME
---------- ------------------------------
1 A
SQL> SELECT /*+ FIRST_ROWS */ * FROM T1 WHERE NAME = 'a';
ID NAME
---------- ------------------------------
1 A
SQL> ALTER SESSION SET NLS_SORT = BINARY;
会话已更改。
SQL> ALTER SESSION SET NLS_COMP = BINARY;
会话已更改。
SQL> SELECT /*+ FIRST_ROWS */ * FROM T1 WHERE NAME LIKE 'A%';
ID NAME
---------- ------------------------------
1 A
SQL> ALTER SESSION SET NLS_COMP = LINGUISTIC;
会话已更改。
SQL> ALTER SESSION SET NLS_SORT = BINARY_CI;
会话已更改。
SQL> SELECT /*+ FIRST_ROWS */ * FROM T1 WHERE NAME LIKE 'A%';
ID NAME
---------- ------------------------------
1 A
SQL> SELECT /*+ FIRST_ROWS */ * FROM T1 WHERE NAME LIKE 'a';
未选定行
通过上面的几个查询可以看到,问题和FIRST_ROWS,LIKE操作以及基于语义的排序直接相关,下面看看Oracle在异常情况下采用了何种执行计划:
SQL> SET AUTOT ON EXP
SQL> SELECT /*+ FIRST_ROWS */ * FROM T1 WHERE NAME LIKE 'a';
未选定行
执行计划
----------------------------------------------------------
Plan hash value: 3350237141
-------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 30 | 35 (0)| 00:00:01 |
|* 1 | VIEW | index$_join$_001 | 1 | 30 | 35 (0)| 00:00:01 |
|* 2 | HASH JOIN | | | | | |
|* 3 | INDEX RANGE SCAN | IND_T1_NAME | 1 | 30 | 3 (34)| 00:00:01 |
| 4 | INDEX FAST FULL SCAN| SYS_C006622 | 1 | 30 | 33 (0)| 00:00:01 |
-------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("NAME" LIKE 'a')
2 - access(ROWID=ROWID)
3 - access("NAME" LIKE 'a')
Note
-----
- dynamic sampling used for this statement
由于索引中并不包含语义查询的结果,因此Oracle这里必须访问表才能得到最终的结果,因此这个执行计划是错误的:
SQL> SELECT * FROM T1 WHERE NAME = 'a';
ID NAME
---------- ------------------------------
1 A
执行计划
----------------------------------------------------------
Plan hash value: 3617692013
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 30 | 3 (0)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| T1 | 1 | 30 | 3 (0)| 00:00:01 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(NLSSORT("NAME",'nls_sort=''BINARY_CI''')=HEXTORAW('6100')
)
Note
-----
- dynamic sampling used for this statement
SQL> SELECT /*+ INDEX(T1) */ * FROM T1 WHERE NAME = 'a';
ID NAME
---------- ------------------------------
1 A
执行计划
----------------------------------------------------------
Plan hash value: 159298173
-------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 30 | 827 (1)| 00:00:10 |
|* 1 | TABLE ACCESS BY INDEX ROWID| T1 | 1 | 30 | 827 (1)| 00:00:10 |
| 2 | INDEX FULL SCAN | SYS_C006622 | 26 | | 26 (0)| 00:00:01 |
-------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(NLSSORT("NAME",'nls_sort=''BINARY_CI''')=HEXTORAW('6100') )
Note
-----
- dynamic sampling used for this statement
上面的两个执行计划已经说明了问题的关键,Oracle对于语义的排序无法通过索引获取,必须要访问表或者相应的函数索引,详细描述可以参考文章开头部分给出的链接。
而采用了FIRST_ROWS优化模式后,当操作为LIKE时,Oracle优化器选择了错误的执行计划进行了优化,采用索引的范围扫描代替了表,从而引发了错误:
SQL> SELECT /*+ INDEX_JOIN(T1 IND_T1_NAME SYS_C006622) */ *
2 FROM T1
3 WHERE NAME LIKE 'a';
未选定行
执行计划
----------------------------------------------------------
Plan hash value: 3350237141
-------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 30 | 35 (0)| 00:00:01 |
|* 1 | VIEW | index$_join$_001 | 1 | 30 | 35 (0)| 00:00:01 |
|* 2 | HASH JOIN | | | | | |
|* 3 | INDEX RANGE SCAN | IND_T1_NAME | 1 | 30 | 3 (34)| 00:00:01 |
| 4 | INDEX FAST FULL SCAN| SYS_C006622 | 1 | 30 | 33 (0)| 00:00:01 |
-------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("NAME" LIKE 'a')
2 - access(ROWID=ROWID)
3 - access("NAME" LIKE 'a')
Note
-----
- dynamic sampling used for this statement
现在没有使用FIRST_ROWS,而采用HINT也达到了相同的效果。而解决这个问题的方法就是通过HINT来避免索引范围扫描的发生。
SQL> ALTER SESSION SET OPTIMIZER_MODE = FIRST_ROWS;
会话已更改。
SQL> SELECT * FROM T1 WHERE NAME LIKE 'a';
未选定行
执行计划
----------------------------------------------------------
Plan hash value: 3350237141
-------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 30 | 35 (0)| 00:00:01 |
|* 1 | VIEW | index$_join$_001 | 1 | 30 | 35 (0)| 00:00:01 |
|* 2 | HASH JOIN | | | | | |
|* 3 | INDEX RANGE SCAN | IND_T1_NAME | 1 | 30 | 3 (34)| 00:00:01 |
| 4 | INDEX FAST FULL SCAN| SYS_C006622 | 1 | 30 | 33 (0)| 00:00:01 |
-------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("NAME" LIKE 'a')
2 - access(ROWID=ROWID)
3 - access("NAME" LIKE 'a')
Note
-----
- dynamic sampling used for this statement
SQL> SELECT /*+ FULL(T1) */ * FROM T1 WHERE NAME LIKE 'a';
ID NAME
---------- ------------------------------
1 A
执行计划
----------------------------------------------------------
Plan hash value: 3617692013
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 30 | 3 (0)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| T1 | 1 | 30 | 3 (0)| 00:00:01 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("NAME" LIKE 'a')
Note
-----
- dynamic sampling used for this statement
SQL> SELECT /*+ NO_INDEX(T1) */ * FROM T1 WHERE NAME LIKE 'a';
ID NAME
---------- ------------------------------
1 A
执行计划
----------------------------------------------------------
Plan hash value: 3617692013
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 30 | 3 (0)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| T1 | 1 | 30 | 3 (0)| 00:00:01 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("NAME" LIKE 'a')
Note
-----
- dynamic sampling used for this statement
查询metalink,Oracle在Doc ID: Note:5252496.8明确说明了这个bug,这个bug会在Oracle10.2.0.4和11.1.0.6中被Fixed。
$(document).ready(function(){dp.SyntaxHighlighter.HighlightAll('code');});
原文链接:
http://blog.csdn.net/newhappy2008/article/details/2316044
相关文章推荐
- FIRST_ROWS优化模式语言排序模糊匹配问题
- FIRST_ROWS优化模式语言排序模糊匹配问题
- FIRST_ROWS优化模式语言排序模糊匹配问题
- FIRST_ROWS优化模式语言排序模糊匹配问题
- FIRST_ROWS优化模式语言排序模糊匹配问题
- Oracle执行计划——all_rows和first_rows(n) 优化器模式
- Oracle执行计划——all_rows和first_rows(n) 优化器模式
- Oracle执行计划——all_rows和first_rows(n) 优化器模式
- 优化模式区别(all_rows & first_rows_n)
- 优化模式区别(all_rows & first_rows_n)
- 【优化】ALL_ROWS模式和FIRST_ROWS模式的适用场景
- 多模式匹配算法,高效解决词典很大的模糊匹配问题
- 产品设计 置顶排序问题以及免刷新流量优化策略
- SQL中常用模糊查询的四种匹配模式&&正则表达式
- MS sqlserver2000 master库语言排序规则不一致导致的问题
- 机房重构(二)--MDI窗体问题+优化的单例模式
- Visual Studio 2015使用EF6的CodeFirstFromDB模式操作Sqlite数据库时Provider问题
- sql查询模糊匹配Like的没数据一个问题
- SQL中常用模糊查询的四种匹配模式&&正则表达式
- 模糊排序问题(Fuzzy sort)