ORACLE外键和锁

在oracle中,如果外键未加索引,对父表的修改,会导致子表被加上全表锁。这包括两种情况:

1.删除父表中的行,如果外键上没有索引,会导致子表被加上全表锁

2.更新父表的主键(根据关系数据库的原则,更新主键是一个巨大的”禁忌”,所以一般不会出现这种情况),如果外键上没有索引,会导致子表被加上全表锁

虽然,在Oracle9i及以上的版本中,这些全表锁都是短期的,他们仅在DML操作期间存在,而不是在整个事务的期间都存在。但是即使如此,这些全表锁还是可能(而且确实会)导致很严重的锁定问题。

可以通过如下语句,查询是否存在未加索引的外键:

SELECT TABLE_NAME,
       CONSTRAINT_NAME,
       CNAME1 || NVL2(CNAME2, ‘, ‘ || CNAME2, NULL) ||
       NVL2(CNAME3, ‘, ‘ || CNAME3, NULL) ||
       NVL2(CNAME4, ‘, ‘ || CNAME4, NULL) ||
       NVL2(CNAME5, ‘, ‘ || CNAME5, NULL) ||
       NVL2(CNAME6, ‘, ‘ || CNAME6, NULL) ||
       NVL2(CNAME7, ‘, ‘ || CNAME7, NULL) ||
       NVL2(CNAME8, ‘, ‘ || CNAME8, NULL) COLUMNS
  FROM (SELECT B.TABLE_NAME,
               B.CONSTRAINT_NAME,
               MAX(DECODE(POSITION, 1, COLUMN_NAME, NULL)) CNAME1,
               MAX(DECODE(POSITION, 2, COLUMN_NAME, NULL)) CNAME2,
               MAX(DECODE(POSITION, 3, COLUMN_NAME, NULL)) CNAME3,
               MAX(DECODE(POSITION, 4, COLUMN_NAME, NULL)) CNAME4,
               MAX(DECODE(POSITION, 5, COLUMN_NAME, NULL)) CNAME5,
               MAX(DECODE(POSITION, 6, COLUMN_NAME, NULL)) CNAME6,
               MAX(DECODE(POSITION, 7, COLUMN_NAME, NULL)) CNAME7,
               MAX(DECODE(POSITION, 8, COLUMN_NAME, NULL)) CNAME8,
               COUNT(*) COL_CNT
          FROM (SELECT SUBSTR(TABLE_NAME, 1, 30) TABLE_NAME,
                       SUBSTR(CONSTRAINT_NAME, 1, 30) CONSTRAINT_NAME,
                       SUBSTR(COLUMN_NAME, 1, 30) COLUMN_NAME,
                       POSITION
                  FROM USER_CONS_COLUMNS) A,
               USER_CONSTRAINTS B
         WHERE A.CONSTRAINT_NAME = B.CONSTRAINT_NAME
           AND B.CONSTRAINT_TYPE = ‘R‘
         GROUP BY B.TABLE_NAME, B.CONSTRAINT_NAME) CONS
 WHERE COL_CNT > ALL (SELECT COUNT(*)
          FROM USER_IND_COLUMNS I
         WHERE I.TABLE_NAME = CONS.TABLE_NAME
           AND I.COLUMN_NAME IN (CNAME1,
                                 CNAME2,
                                 CNAME3,
                                 CNAME4,
                                 CNAME5,
                                 CNAME6,
                                 CNAME7,
                                 CNAME8)
           AND I.COLUMN_POSITION <= CONS.COL_CNT
         GROUP BY I.INDEX_NAME)

这个脚本将最多处理8列外键约束(如果你的外键有更多的列,可能就得重新考虑一下你的设计了)!

除了全表锁外,在以下情况下,未加索引的外键也可能带来问题:

     1.如果有on delete cascade,而且没有对子表加索引:例如,emp是dept的子表,delete deptno=10应该cascade(级联)至emp。如果emp中的deptno没有索引,那么删除dept表中的每一行时都会对emp做一次全表扫描。这个全表扫描可能是不必要的,而且如果从父表删除多行,父表中每删除一行就要扫描仪一次子表。

2.从父表查询子表:在此考虑emp/dept例子。利用deptno查询emp表是相当常见的。如果频繁地运行以下查询,你就会发现没有索引会使查询速度变慢:

select *
     from dept, emp
    where emp.deptno=dept.deptno
      and dept.deptno=:x;

所以,要特表注意是否需要对外键加索引,防止出现这种Oracle“过分地锁定了”数据的情况。

 

                                                                                                                                                        --参考自《Oracle专家高级编程》

时间: 2024-10-06 01:14:41

ORACLE外键和锁的相关文章

Oracle外键不加索引引起死锁

--创建一个表,此表作为子表 create table fk_t as select *from user_objects; delete from  fk_t where object_id is null; commit; --创建一个表,此表作为父表 create table pk_t as select *from user_objects; delete from  pk_t where object_id is null; commit; --创建父表的主键 alter table

Oracle外键级联删除和级联更新

1 级联删除 Oracle在外键的删除上有NO ACTION(类似RESTRICT).CASCADE和SET NULL三种行为. 下面以学生-班级为例说明不同情况下的外键删除,学生属于班级,班级的主键是学生的外键. -- 班级表 CRATE TABLE TB_CLASS ( ID NUMBER NOT NULL, --班级主键 NAME VARCHAR2(50), --班级名称 CONSTRAINT PK_TB_CLASS PRIMARY KEY (ID) ); -- 学生表 CREATE TA

Oracle外键需要建索引吗?

关于Oracle中的外键,首先要说明一下. 1. 除非已定义了父表主键或唯一键约束,否则oracle将不允许创建子表的外键约束. 2. 在定义外键约束时,oracle不会自动创建索引,所以必须手动在与外键约束相关的列上创建索引. 所以我们这里要研究的是否需要在子表中创建索引,因为父表中对应的列是一定有索引的. 如果子表中的外键不创建索引,将导致两个问题. 1. 影响性能. 如果子表外键没有创建索引,那么当父表查询关联子表时,子表将进行全表扫描. 2. 影响并发. 如果子表外键没有创建索引,那么在

Oracle 外键约束子表、父表

CREATE TABLE employees( employee_id      NUMBER(6), last_name        VARCHAR2(25) NOT NULL, email            VARCHAR2(25), salary           NUMBER(8,2), commission_pct   NUMBER(2,2), hire_date        DATE NOT NULL, ... department_id    NUMBER(4), CON

MySQL锁类型(一致性是非锁定读、自增和外键)

1.一致性的非锁定读 一致性的非锁定读(consistent nonlocking read)是指InnoDB存储引擎通过行多版本控制(multi versionning)的方式来读取当前执行时间数据库中行的数据.如果读取的行正在执行DELETE或UPDATE操作,这时读取操作不会因此去等待行上锁的释放,相反地,InnoDB存储引擎会去读取行地一个快照数据. 快照数据是指该行地之前版本地数据,该实现是通过undo段来完成.而undo用来在事务中回滚数据,因此快照数据本身是没有额外地开销.此外,读

Oracle之外键(Foreign Key)用法详解(二)- 级联删除(DELETE CASCADE)

Oracle外键(Foreign Key)之级联删除(DELETE CASCADE) 目标 示例讲解如何在Oracle外键中使用级联删除 什么是级联删除(DELETE CASCADE)? 级联删除是指当主表(parent table)中的一条记录被删除,子表中关联的记录也相应的自动删除. 外键的级联删除可以在创建表时定义,也可以使用ALTER TABLE语法定义. 创建表时定义级联删除 语法: CREATE TABLE table_name ( column1 datatype null/not

Oracle之外键(Foreign Key)用法详解(一)

Oracle外键(Foreign Key)用法详解(一) 1.目标 演示如何在Oracle数据库中使用外键 2.什么是外键? 1)在Oracle数据库中,外键是用来实现参照完整性的方法之一.打个形象的比喻,外键是指定义外键的表的列的值必须在另一个表中出现. 2)被参照的表称之为父表(parent table),创建外键的表称之为子表(child table).子表中的外键关联了父表中的主键. 3)外键可以在创建表时定义或者通过ALTER TABLE语句创建. 3.创建表时定义外键 语法: CRE

通过在Oracle子表外键上建立索引提高性能

根据我的经验,导致死锁的头号原因是外键未加索引(第二号原因是表上的位图索引遭到并发更新).在以下两种情况下,Oracle在修改父表后会对子表加一个全表锁: 1)如果更新了父表的主键(倘若遵循关系数据库的原则,即主键应当是不可变的,这种情况就很少见),由于外键上没有索引,所以子表会被锁住. 2) 如果删除了父表中的一行,整个子表也会被锁住(由于外键上没有索引). 除了全表锁外,在以下情况下,未加索引的外键也可能带来问题: 1) 如果有ON DELETE CASCADE,而且没有对子表加索引:例如,

mysql外键引发的锁等待

有这样两条sql: insert table_a (bId) value(1); -- sql-1  update table_b set b.xx=123 where b.id =1; -- sql-2 其中,table_a的字段bId是个外键:外键关联的正是table_b的id字段. 在mysql上执行这两条数据时,sql-1会锁住sql-2.我们的系统中,为这一个锁,发生了不知道多少的锁等待,更引发了不知道多少的死锁. 特此备忘.