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
會話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 回滾段的味道