Oracle 大表建立索引

Oracle 大表建立索引

祖仙教小凡仙 海鯊數據庫架構師 數據庫

有個2億記錄的表,發現須要添加一個聯合索引,結果就採用普通的create index index_name on tablename (entp_id,sell_date),結果悲劇了,把全部的DML語句都阻塞了,致使系統不能正常使用,還好是晚上10點,用戶不是很是多,1個小時候,索引結束,阻塞解決;上網查了一下,若是加上 online參數後,就能夠在線作索引,而不須要阻塞全部的DML語句,血的教訓,拿出來與各位共勉,架構

建立測試表ide

* create table t_test
* (
*   col1 number,
*   col2 number
* );

造測試數據(根據本身機器具體狀況估計須要的數據量,使建立索引的時間大概在20-30秒)測試

  • insert into t_test
  • select rownum col1, rownum col2 from dual
  • connect by rownum<10000000;
  • commit;

create indexcode

會話1:索引

  • SQL> set time on
  • 10:22:01 SQL> set timing on
  • 10:22:02 SQL>
  • --獲取 會話1 sid
  • 10:22:04 SQL> select sid from v$mystat where rownum=1;
  • SID

  • 144
  • Elapsed: 00:00:00.01

會話2:it

  • SQL> set time on
  • 10:22:06 SQL> set timing on
  • 10:22:06 SQL>
  • --獲取 會話2 sid
  • 10:22:06 SQL> select sid from v$mystat where rownum=1;
  • SID

  • 147
  • Elapsed: 00:00:00.01

會話3:table

  • SQL> set time on
  • 10:22:11 SQL> set timing on
  • 10:22:11 SQL>
  • --格式化輸出
  • 10:22:13 SQL> set line 200
  • 10:23:03 SQL> col addr for a10
  • 10:23:03 SQL> col kaddr for a10
  • 10:23:03 SQL> col sid for 999999
  • 10:23:03 SQL> col type for a10
  • 10:23:03 SQL> col id1 for 99999999999
  • 10:23:03 SQL> col id2 for 99999999999
  • 10:23:03 SQL> col lmod for 99
  • 10:23:03 SQL> col request for 99
  • 10:23:03 SQL> col ctime for 999999
  • 10:23:03 SQL> col block for 99
  • 10:23:03 SQL> col table_name for a30
  • 10:23:03 SQL>

會話1:class

  • --建立索引(由於要在 會話二、會話3 中作其它操做,因此表中數據要量要足夠大)
  • 10:25:08 SQL> create index ix_test_col1 on t_test(col1);test

  • Index created.

  • Elapsed: 00:00:59.73

會話2:

  • --修改指定行的索引字段,此時update語句會hang住,等待索引建立,從會話3 中的鎖的狀況能夠看到 會話2 在等待 會話1
  • 10:25:04 SQL> update t_test set col1=102400 where col2=102400;
  • 1 row updated.
  • Elapsed: 00:01:02.63
  • 會話3:

  • --查看此時鎖的狀況
  • 10:24:29 SQL> select a.*, decode(a.type, \'TM\', b.object_name) table_name
  • from v$lock a, dba_objects b
  • where a.id1=b.object_id(+)
  • and a.sid in(144, 147);
  • SID TYPE ID1 ID2 LMODE REQUEST CTIME BLOCK TABLE_NAME

  • 144 TM 18 0 3 0 1 0 OBJ$
  • 147 TM 5180637 0 0 3 0 0 T_TEST
  • 144 TM 5180637 0 4 0 3 1 T_TEST
  • 144 DL 5180637 0 3 0 3 0
  • 144 DL 5180637 0 3 0 3 0
  • 144 TX 655384 57423 6 0 3 0
  • 6 rows selected.
  • Elapsed: 00:00:02.12
  • 10:25:52 SQL> /

這裏看到普通索引建立 要加TM TX DL 三把鎖,更新語句正在等待要加TX鎖

  • SID TYPE ID1 ID2 LMODE REQUEST CTIME BLOCK TABLE_NAME

  • 147 TM 5180637 0 3 0 4 0 T_TEST
  • 147 TX 393221 56619 6 0 4 0
  • Elapsed: 00:00:00.77

當索引建立完 了後 更新語句才加到鎖.

所以普通索引建立的時候 會阻塞 索引字段上的DML操做! 主要是由於不喜歡別的會話更改索引字段的值,不然致使索引葉節點的鍵值與表數據不一致.

create index online

會話1:

  • --刪除索引,並加online選項重建
  • 10:26:46 SQL> drop index ix_test_col1;
  • Index dropped.
  • Elapsed: 00:00:00.35
  • 10:26:59 SQL> create index ix_test_col1 on t_test(col1) online;
  • Index created.
  • Elapsed: 00:02:47.07
  • 會話2:

  • --修改指定行的索引字段,此時update不會待索引建立,而是很快結束
  • 10:26:50 SQL> update t_test set col1=102400 where col2=102400;
  • 1 row updated.
  • Elapsed: 00:00:09.21
  • 會話3:

  • --查看鎖的狀況
  • 10:26:53 SQL> /
  • SID TYPE ID1 ID2 LMODE REQUEST CTIME BLOCK TABLE_NAME

  • 147 TM 5180637 0 3 0 6 0 T_TEST
  • 144 TM 5180637 0 2 0 7 0 T_TEST
  • 144 DL 5180637 0 3 0 8 0
  • 144 DL 5180637 0 3 0 8 0
  • 144 TM 5180671 0 4 0 7 0 144 TX 327692 57125 6 0 8 0
  • 147 TX 655370 57432 6 0 6 0
  • 7 rows selected.
  • Elapsed: 00:00:02.16

這裏看到DML語句也加到了TX鎖,而索引也加了3把鎖.

.online建立索引時會臨時建立一個IOT的表,把後期DML 記錄到該表中,索引建立結束後刪除IOT表 事實上就是相似於MVCC 回滾段的味道

相關文章
相關標籤/搜索