暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Oracle 大表创建索引

IT界数据库架构师的漂泊人生 2020-12-14
2706


有个2亿记录的表,发现需要添加一个联合索引,结果就采用普通的create index index_name on tablename (entp_id,sell_date),结果悲剧了,把所有的DML语句都阻塞了,导致系统不能正常使用,还好是晚上10点,用户不是非常多,1个小时候,索引结束,阻塞解决;上网查了一下,如果加上 online参数后,就可以在线做索引,而不需要阻塞所有的DML语句,血的教训,拿出来与各位共勉,

创建测试表

  1. create table t_test

  2. (

  3.   col1 number,

  4.   col2 number

  5. );


造测试数据(根据自己机器具体情况估计需要的数据量,使创建索引的时间大概在20-30秒

  1. insert into t_test

  2. select rownum col1, rownum col2 from dual

  3. connect by rownum<10000000;

  4. commit;


create index

会话1:

  1. SQL> set time on

  2. 10:22:01 SQL> set timing on

  3. 10:22:02 SQL> 


  4. --获取 会话1 sid

  5. 10:22:04 SQL> select sid from v$mystat where rownum=1;


  6.        SID 

  7. ---------- 

  8.        144 


  9. Elapsed: 00:00:00.01


会话2:

  1. SQL> set time on

  2. 10:22:06 SQL> set timing on

  3. 10:22:06 SQL> 


  4. --获取 会话2 sid

  5. 10:22:06 SQL> select sid from v$mystat where rownum=1;


  6.        SID 

  7. ---------- 

  8.        147 


  9. Elapsed: 00:00:00.01


会话3:

  1. SQL> set time on

  2. 10:22:11 SQL> set timing on

  3. 10:22:11 SQL> 


  4. --格式化输出

  5. 10:22:13 SQL> set line 200

  6. 10:23:03 SQL> col addr for a10

  7. 10:23:03 SQL> col kaddr for a10

  8. 10:23:03 SQL> col sid for 999999

  9. 10:23:03 SQL> col type for a10

  10. 10:23:03 SQL> col id1 for 99999999999

  11. 10:23:03 SQL> col id2 for 99999999999

  12. 10:23:03 SQL> col lmod for 99

  13. 10:23:03 SQL> col request for 99

  14. 10:23:03 SQL> col ctime for 999999

  15. 10:23:03 SQL> col block for 99

  16. 10:23:03 SQL> col table_name for a30

  17. 10:23:03 SQL>


会话1:

  1. --创建索引(因为要在 会话2、会话3 中做其它操作,所以表中数据要量要足够大)

  2. 10:25:08 SQL> create index ix_test_col1 on t_test(col1);


  3. Index created.


  4. Elapsed: 00:00:59.73


会话2:

  1. --修改指定行的索引字段,此时update语句会hang住,等待索引创建,从会话3 中的锁的情况可以看到 会话2 在等待 会话1

  2. 10:25:04 SQL> update t_test set col1=102400 where col2=102400;


  3. row updated.


  4. Elapsed: 00:01:02.63


会话3:

  1. --查看此时锁的情况

  2. 10:24:29 SQL> select a.*, decode(a.type, \'TM\', b.object_name) table_name

     from v$lock a, dba_objects b

  3.  where a.id1=b.object_id(+)

  4.  and a.sid in(144, 147);


  5. SID     TYPE       ID1          ID2          LMODE      REQUEST CTIME   BLOCK TABLE_NAME 

  6. ---------- ---------- ------- ---------- ------------ ------------ ---------- ------- -----

  7.  144     TM                        18           0            3          0       1       0     OBJ$ 

  8. 147     TM         5180637      0            0          3       0       0     T_TEST 

  9. 144     TM         5180637      0            4          0       3       1     T_TEST 

  10. 144     DL         5180637      0            3          0       3       0 

  11. 144     DL         5180637      0            3          0       3       0 

  12. 144     TX         655384       57423        6          0       3       0 


  13. rows selected.


  14. Elapsed: 00:00:02.12

  15. 10:25:52 SQL> /


这里看到普通索引创建 要加TM TX DL 三把锁,更新语句正在等待要加TX锁


  1.  SID     TYPE       ID1          ID2          LMODE      REQUEST CTIME   BLOCK TABLE_NAME 

  2. ---------- ---------- ------- ---------- ------------ ------------ ---------- ------- ------- ----- ------------------------------ 

  3. 147     TM         5180637      0            3          0       4       0     T_TEST 

  4.   147     TX         393221       56619        6          0       4       0 


  5. Elapsed: 00:00:00.77


当索引创建完 了后 更新语句才加到锁.

因此普通索引创建的时候 会阻塞 索引字段上的DML操作! 主要是因为不喜欢别的会话更改索引字段的值,否则导致索引叶节点的键值与表数据不一致.


create index online

会话1:

  1. --删除索引,并加online选项重建

  2. 10:26:46 SQL> drop index ix_test_col1;


  3. Index dropped.


  4. Elapsed: 00:00:00.35

  5. 10:26:59 SQL> create index ix_test_col1 on t_test(col1) online;


  6. Index created.


  7. Elapsed: 00:02:47.07


会话2:

  1. --修改指定行的索引字段,此时update不会待索引创建,而是很快结束

  2. 10:26:50 SQL> update t_test set col1=102400 where col2=102400;


  3. row updated.


  4. Elapsed: 00:00:09.21


会话3:

  1. --查看锁的情况

  2. 10:26:53 SQL> /

  3. SID     TYPE       ID1          ID2          LMODE      REQUEST CTIME   BLOCK TABLE_NAME 

  4. ---------- ---------- ------- ---------- ------------ ------------ ---------- ------- ------- ----- ------------------------------ 

  5. 147     TM         5180637      0            3          0       6       0     T_TEST 

  6. 144     TM         5180637      0            2          0       7       0     T_TEST 

  7. 144     DL         5180637      0            3          0       8       0 

  8. 144     DL         5180637      0            3          0       8       0 

  9. 144     TM         5180671      0            4          0       7       0      144     TX         327692       57125        6          0       8       0 

  10. 147     TX         655370       57432        6          0       6       0 


  11. rows selected.


  12. Elapsed: 00:00:02.16



这里看到DML语句也加到了TX锁,而索引也加了3把锁.

.online创建索引时会临时创建一个IOT的表,把后期DML 记录到该表中,索引创建结束后删除IOT表 事实上就是类似于MVCC 回滚段的味道



文章转载自IT界数据库架构师的漂泊人生,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论