newhappy的专栏

高级系统分析师,专注于对SOA,Ajax以及J2EE架构的研究,欢迎大家与我交流.Email:pleasechess@126.com

牛海彬ID:newhappy2008
461167次访问,排名94好友25人,关注者22
吉林大学软件工程硕士;一汽启明CPDM项目组软件工程师;
newhappy2008的文章
原创 183 篇
翻译 24 篇
转载 99 篇
评论 241 篇
newhappy的公告
非常感谢CSDN提供了这么好的一个平台,过去的一年为生活而忙忙碌碌,博客更新的不多,在新的一年里,我会勤快一点,多学一些技术,多交一些技术上的朋友.
最近评论
hdnero:wow power leveling
hblhshb:建索引之前可以以这个为参考,有没有必要建相应列的索引

ajax_jiaocheng:辛苦了,非常精彩的文章.感谢博主分享 :)
liuxinyao:抽出来的简化步骤就是

//定义数据库连接
Connection conn = null;
DriverManager.registerDriver(new com.microsoft.jdbc.sqlserver.SQLServerDriver());
//连接数据库
conn=DriverManager.getConnect……
qing_zhang:那读出来呢???
文章分类
收藏
    相册
    友情连接
    114社区
    SOA-中间件
    张孝祥(RSS)
    杨洪波(RSS)
    沈东良
    许式伟(RSS)
    谭振林(RSS)
    银狐999(RSS)
    阿蒙专栏(RSS)
    存档
    软件项目交易
    订阅我的博客
    XML聚合  FeedSky
    订阅到鲜果
    订阅到Google
    订阅到抓虾
    订阅到BlogLines
    订阅到Yahoo
    订阅到GouGou
    订阅到飞鸽
    订阅到Rojo
    订阅到newsgator
    订阅到netvibes

    转载 FIRST_ROWS优化模式语言排序模糊匹配问题 收藏

    新一篇: 使用Java实现在SQLserver中实现图片的存储

    标题比较长,不过只有这样才能把问题描述清楚。

    问题详细描述为,在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_ROWSLIKE操作以及基于语义的排序直接相关,下面看看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

    查询metalinkOracleDoc ID: Note:5252496.8明确说明了这个bug,这个bug会在Oracle10.2.0.4和11.1.0.6中被Fixed

     

     

    发表于 @ 2008年04月22日 19:57:00|评论(loading...)|编辑

    旧一篇: 在Oracle中进行大小写不敏感的查询

    评论:没有评论。

    发表评论  


    当前用户设置只有注册用户才能发表评论。如果你没有登录,请点击登录
    Csdn Blog version 3.1a
    Copyright © newhappy