Decode360's Blog

          業精于勤而荒于嬉 QQ:150355677 MSN:decode360@hotmail.com

            BlogJava :: 首頁 :: 新隨筆 :: 聯系 ::  :: 管理 ::
            302 隨筆 :: 26 文章 :: 82 評論 :: 0 Trackbacks
          ??? 今天工作上遇到了一個問題,一個好幾萬數據的大表update數據時不走索引,時間長到無法忍受。建一個環境模擬一下:
          ?
          create table t1_a(a int,b varchar2(100),c varchar2(100));
          create table t1_b(a varchar2(2),bb varchar2(100),cc varchar2(100));
          ?
          create index t1_a_idx on t1_a(a);
          create index t1_b_idx on t1_b(a);
          ?
          insert into t1_a values(1,'b1','c1');
          insert into t1_a values(2,'b2','c2');
          insert into t1_a values(3,'b3','c3');
          insert into t1_a values(4,'b4','c4');
          insert into t1_a values(5,'b5','c5');
          insert into t1_b values('1','bb1','cc1');
          insert into t1_b values('2','bb2','cc2');
          insert into t1_b values('3','bb3','cc3');
          insert into t1_b values('4','bb4','cc4');
          insert into t1_b values('5','bb5','cc5');
          ?
          commit;
          ?
          ?
          ??? 用來update的SQL是這樣的:
          ?
          update t1_a set (b,c) = (select bb,cc from t1_b where a=t1_a.a);
          ?
          Execution Plan
          ----------------------------------------------------------
          ?? 0????? UPDATE STATEMENT Optimizer=ALL_ROWS (Cost=3 Card=5 Bytes=585)
          ?? 1??? 0?? UPDATE OF 'T1_A'
          ?? 2??? 1???? TABLE ACCESS (FULL) OF 'T1_A' (TABLE) (Cost=3 Card=5 Bytes=585)
          ?? 3??? 1???? TABLE ACCESS (FULL) OF 'T1_B' (TABLE) (Cost=3 Card=1 Bytes=107)

          ??? 上網看了一下,發現有人遇到跟我一樣的問題,連原因也一樣,具體網址:http://space.itpub.net/16179598/viewspace-539595
          ?
          ??? 在t1_a表的a字段外加上to_char函數后,使用索引:
          ?
          update t1_a set (b,c) = (select bb,cc from t1_b where a=to_char(t1_a.a));
          ?
          Execution Plan
          ----------------------------------------------------------
          ?? 0????? UPDATE STATEMENT Optimizer=ALL_ROWS (Cost=3 Card=5 Bytes=585)
          ?? 1??? 0?? UPDATE OF 'T1_A'
          ?? 2??? 1???? TABLE ACCESS (FULL) OF 'T1_A' (TABLE) (Cost=3 Card=5 Bytes=585)
          ?? 3??? 1???? TABLE ACCESS (BY INDEX ROWID) OF 'T1_B' (TABLE) (Cost=2 Card=1 Bytes=107)
          ?? 4??? 3?????? INDEX (RANGE SCAN) OF 'T1_B_IDX' (INDEX) (Cost=1 Card=1)
          ?
          ??? 這樣速度就快很多了,主要原因是oracle自動進行類型轉換之后就不再走索引了。
          ?
          ?
          drop table t1_a;
          drop table t1_b;
          set autotrace off;?
          ?
          ?
          ?
          因為實際中是由于varchar2與nvarchar2類型不匹配造成,所以轉一篇NVARCHAR2類型介紹的帖子
          =========================================================== ===========================================================
          ?
          輸入NVARCHRA2類型字符串
          ===========================================================

          今天看到論壇的一個帖子,是關于NVARCHAR2字符串的。解答之后,順便問了問同事,發現居然大家都不知道這個語法。所以這里簡單描述一下。


          其實語法非常檢查,要指定一個國家字符集的字符串NCHARNVARCHAR2,只需要在字符串前面加上一個N就可以了。

          舉個例子:

          SQL> CREATE TABLE T_NVARCHAR2 (ID NUMBER, NAME NVARCHAR2(30));

          表已創建。

          SQL> INSERT INTO T_NVARCHAR2 VALUES (1, N'ABC');

          已創建 1 行。

          SQL> DROP TABLE T_NVARCHAR2 PURGE;

          表已刪除。

          SQL> CREATE TABLE T_NVARCHAR2 (ID NUMBER, NAME NVARCHAR2(30));

          表已創建。

          SQL> INSERT INTO T_NVARCHAR2 VALUES (1, N'ABC');

          已創建 1 行。

          SQL> COMMIT;

          提交完成。

          SQL> SELECT DUMP(NAME, 16) FROM T_NVARCHAR2;

          DUMP(NAME,16)
          ---------------------------------------------------------------------------------------
          Typ=1 Len=6: 0,41,0,42,0,43

          SQL> SELECT DUMP('ABC', 16) VAR, DUMP(N'ABC', 16) NVAR FROM DUAL;

          VAR NVAR
          -------------------------------------------- ----------------------------------------
          Typ=96 Len=3: 41,42,43 Typ=96 Len=6: 0,41,0,42,0,43

          如果對于VARCHAR2類型的表指定NVARCHAR2類型的查詢,Oracle會自動進行隱式類型轉換。

          SQL> CREATE TABLE T (ID NUMBER, NAME VARCHAR2(30));

          表已創建。

          SQL> CREATE INDEX IND_T_NAME ON T(NAME);

          索引已創建。

          SQL> INSERT INTO T SELECT ROWNUM, OBJECT_NAME FROM ALL_OBJECTS;

          已創建54020行。

          SQL> COMMIT;

          提交完成。

          SQL> SET AUTOT ON EXP
          SQL> SELECT * FROM T WHERE NAME = 'T';

          ID NAME
          ---------- ------------------------------
          53170 T

          執行計劃
          ----------------------------------------------------------
          Plan hash value: 1889074194

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

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

          2 - access("NAME"='T')

          Note
          -----
          - dynamic sampling used for this statement

          SQL> SELECT * FROM T WHERE NAME = N'T';

          ID NAME
          ---------- ------------------------------
          53170 T

          執行計劃
          ----------------------------------------------------------
          Plan hash value: 2153619298

          --------------------------------------------------------------------------
          | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
          --------------------------------------------------------------------------
          | 0 | SELECT STATEMENT | | 1 | 30 | 52 (6)| 00:00:01 |
          |* 1 | TABLE ACCESS FULL| T | 1 | 30 | 52 (6)| 00:00:01 |
          --------------------------------------------------------------------------

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

          1 - filter(SYS_OP_C2C("NAME")=U'T')

          Note
          -----
          - dynamic sampling used for this statement

          這個隱式轉換過程會將列字段的VARCHAR2類型轉換為NVARCHAR2類型,導致索引無法使用。如果想要這種情況下仍然可以使用索引,需要建立一個函數索引:

          SQL> CREATE INDEX IND_T_NNAME ON T(TO_NCHAR(NAME));

          索引已創建。

          SQL> SELECT * FROM T WHERE NAME = N'T';

          ID NAME
          ---------- ------------------------------
          53170 T

          執行計劃
          ----------------------------------------------------------
          Plan hash value: 462587453

          -------------------------------------------------------------------------------------------
          | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
          -------------------------------------------------------------------------------------------
          | 0 | SELECT STATEMENT | | 567 | 60669 | 48 (0)| 00:00:01 |
          | 1 | TABLE ACCESS BY INDEX ROWID| T | 567 | 60669 | 48 (0)| 00:00:01 |
          |* 2 | INDEX RANGE SCAN | IND_T_NNAME | 227 | | 1 (0)| 00:00:01 |
          -------------------------------------------------------------------------------------------

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

          2 - access(SYS_OP_C2C("NAME")=U'T')

          Note
          -----
          - dynamic sampling used for this statement

          yangtingkun 發表于:2009.01.07 22:15 ::分類: ( ORACLE ) ::閱讀:(344次) :: 評論 (1)
          ?
          ?




          -The End-

          posted on 2009-01-26 18:16 decode360-3 閱讀(906) 評論(0)  編輯  收藏 所屬分類: SQL Dev
          主站蜘蛛池模板: 福安市| 泾源县| 繁昌县| 二连浩特市| 石门县| 平谷区| 阳高县| 达拉特旗| 东阿县| 昭苏县| 安仁县| 永德县| 双鸭山市| 景泰县| 开封市| 澄城县| 松溪县| 上林县| 弥渡县| 塔城市| 都安| 石嘴山市| 祥云县| 文登市| 应城市| 北碚区| 巴东县| 青铜峡市| 武川县| 临邑县| 赤城县| 井陉县| 富川| 阳谷县| 江华| 綦江县| 广西| 连山| 新乡市| 中牟县| 双牌县|