• 创建索引资源正忙的解决方案及原理


    GPS平台、网站建设、软件开发、系统运维,找森大网络科技!
    https://cnsendnet.taobao.com
    来自森大科技官方博客
    http://www.cnsendblog.com/index.php/?p=2128

    问题回顾:

    创建索引的时候报错ORA-00054: resource busy and acquire with NOWAIT specified

    解决步骤:

    1:等待其他会话释放资源

    2:找出占用资源的会话,并删除 

    3:重启数据库

    原理分析:    

    1:创建索引时会产生的锁

    2:dml 语句会产生的锁

    3:索引创建时加上关键字 online时产生的锁

    问题回顾

    1. 1

    创建索引时失败报错

    create index sa.idx_test_1_id on sa.test_1 (id);

    NOWAIT :关键字表示sql语句采用非阻塞的方式,如果发现涉及到的数据被占有(被锁),则立即通知Oracle该资源被占用,返回错误信息

     

    方法/步骤2

    1. 1

    等待其他会话释放资源

    在创建语句中添加online,会话释放资源之后,该语句会自动执行。

    create index sa.idx_test_1_id on sa.test_1 (id) online;

    这种方式是采用阻塞方式,不报错

     

    找出占用资源的会话,并删除 

    1:找出所有被锁的对象,定位出哪个回话占用

    select l.session_id,o.owner,o.object_name

    from v$locked_object l,dba_objects o

    where l.object_id=o.object_id

    结果:

    session_id owner object_name

    158 SA TEST_1

    146 SA TEST_1

    131 SA TEST_3

    136 SA TEST_2

    对比想要创建的索引,定位哪些会话需要被删除

    2:找出所有照成锁的会话

    select t2.username,t2.sid,t2.serial#,t2.logon_time

    from v$locked_object t1,v$session t2

    where t1.session_id=t2.sid order by t2.logon_time;

    结果:

    username  sid  serial# logon_time

    SA 158 15184 2014/12/4 14:55:59

    SA 146 8229 2014/12/4 15:23:22

    SA 136 14314 2014/12/4 16:09:59

    SA 131 54 2014/12/4 16:10:06

    3kill 所有占用资源的会话

    命令形式:alter system kill session 'sid,serial#';

    占用test_1的资源的会话:

    alter system kill session '158,15184';

    alter system kill session '146 ,8229';

     

    重启数据库

    如果数据不重要的话,可以重启数据库回滚所有未提交事务,将资源释放出来

    END

    原理分析

    1. 创建索引时会产生的锁

    1:查看当前回话号

    SQL> select sid from v$mystat where rownum<2;

    2:创建索引

    SQL> create index sa.idx_clxsgj_HPHM_jgsj on sa.clxsgj(HPHM,jgsj);

    3:查询当前会话号产生的锁

    select rpad(oracle_username, 10) o_name,

    session_id sid,

    decode(locked_mode,

    0,

    'None',

    1,

    'Null',

    2,

    'Row share',

    3,

    'Row Exclusive',

    4,

    'Share',

    5,

    'Share Row Exclusive',

    6,

    'Exclusive') lock_type,

    object_name,

    xidusn,

    xidslot,

    xidsqn

    from v$locked_object, all_objects

    where v$locked_object.object_id = all_objects.object_id 

    and session_id=140

    从图片中可以看出

    在创建索引的时候,会在每个分区产生共享锁(share,并在OBJ$表上产生

    行级排他锁(Row Exclusive

    注释:

    排他锁(row exclusive):行级别,释放前,其他事物不能修改被锁的资源

    共享锁(share):段级别,释放之前,对象上可以继续加其他类型的锁

    共享锁(row share):行级别

    同一个段级不能同时存在sharerow exclusive

    同一个段级row share row exclusive 可以同时存在

    段级:一个普通表、分区表的每个分区、普通索引、索引的每个分区

    行级:一行数据

    锁范围大小:

    EXCLUSIVE > ROW SHARE EXCLUSIVE > SHARE > ROW EXCLUSIVE > ROW SHARE 

    1. dml 语句会产生的锁

    1:连接用

    SQL> conn sa/ednns

    2:执行DML语句,但不提交

    SQL> update CLXSGJ set cdfx=2 where clgjid=300000040044785;

    3:户查看当前回话号

    SQL> select sid from v$mystat where rownum<2;

           SID

    ----------

           140

    4:查看DML语句产生的锁

    select rpad(oracle_username, 10) o_name,

    session_id sid,

    decode(locked_mode,

    0,

    'None',

    1,

    'Null',

    2,

    'Row share',

    3,

    'Row Exclusive',

    4,

    'Share',

    5,

    'Share Row Exclusive',

    6,

    'Exclusive') lock_type,

    object_name,

    xidusn,

    xidslot,

    xidsqn

    from v$locked_object, all_objects

    where v$locked_object.object_id = all_objects.object_id 

    and session_id=140

    从中可以看出

    DML语句会在更新数据所在的分区上产生行级排他锁。

    之前已经

    由于DML语句在CLXSGJ某些分区已经行级排他锁,而create index会对所有分区产生段级共享锁,对象上已经存在的锁不允许比他大一级的锁产生。

    1. 索引创建时加上关键字 online时产生的锁

    加上online 对每个分区仅仅产生ROW SHARE锁,且不会对OBJ$表产生

    ROW EXCLUSIVE,而是产生一个临时表,并在临时表中产生SHARE

    注释:

    ROW EXCLUSIVE 可以允许比他小一级的ROW SHARE 锁产生,所以不会报错

     

    GPS平台、网站建设、软件开发、系统运维,找森大网络科技!
    https://cnsendnet.taobao.com
    来自森大科技官方博客
    http://www.cnsendblog.com/index.php/?p=2128

  • 相关阅读:
    JAVA多线程知识点
    RabbitMQ和Springboot集成RabbitMQ知识点
    JAVA动态代理cglib或jdk
    [转]解决System.Data.SqlClient.SqlException (0x80131904): Timeout 时间已到的问题的一个方向
    [转]C#判断文档编码格式,并读取文档数据(防止出现乱码)
    create_linux命令写入到sh脚本并删除
    cmd cd切换到d盘
    sql 优化前后
    LISTAGG()WITHIN GROUP()
    使用shell递归遍历文件并打印所有文件名的绝对路径
  • 原文地址:https://www.cnblogs.com/cnsend/p/15721392.html
Copyright © 2020-2023  润新知