外键未加索引和加索引的区别(一)

外键索引与锁行为
本文通过实验对比分析了在外键未加索引和加索引两种情况下,对父表和子表进行增删改操作时,Oracle数据库中锁的行为差异。
 
主要描述外键未加索引和加索引的区别:
 
首先建相关表:
create table dept (dept_id number(2), name varchar2(20));   
alter table dept add (constraint pk_dept primary key (dept_id)); 
 
--在外键上没有建索引的子表
CREATE TABLE emp
   (emp_id number(10),
    name varchar2(20) ,
    dept_id number(2) CONSTRAINT fk_emp
                      references dept(dept_id)
                      ON DELETE CASCADE
   );
alter table emp add (constraint pk_emp primary key (emp_id));  
 
insert into dept values (10,'ACCOUNTING'); 
insert into dept values (11,'SALES'); 
insert into dept values (12,'RESEARCH'); 
insert into dept values (14,'TT');  
 
insert into emp values (2001,'Jason',10); 
insert into emp values (2002,'Mike',11); 
insert into emp values (2003,'Green',12); 
insert into emp values (2004,'Grey',10); 
 
外键未加索引情况,实验如下:
实验1、
Session1:对子表进行插入操作:
insert into emp values(2005,'dai',14);
 
session0:此时加锁的信息都是如下:
SQL> @c:/showlock;
O_NAME            SID LOCK_TYPE            OBJECT_NAME         XIDUSN    XIDSLOT     XIDSQN
---------- ---------- -------------------- --------------- ---------- ---------- ----------
DAIMIN            142 Row share            DEPT                    11         12        503
DAIMIN            142 Row Exclusive        EMP                     11         12        503
 
SQL> @c:/showalllock;
       SID TYPE        ID1        ID2 LOCK_TYPE               REQUEST      CTIME      BLOCK
---------- ---- ---------- ---------- -------------------- ---------- ---------- ----------
       142 TM        55606          0 Row share                     0          6          0
       142 TX       720908        503 Exclusive                     0          6          0
       142 TM        55612          0 Row Exclusive                 0          6          0
分析:对子表进行插入操作时,此时尽管只是对子表操作,但是需要验证被插入的记录中的外键值是否在父表中是否存在,不存在,则会报错;存在的话,则允许插入。此时需要对父表加RS锁,锁住外键值所对应父表被引用键值的行;除了对父表加RS锁之外,对子表还要加RX锁和TX锁。
 
实验2、
Session2:对子表EMP进行更新操作,并且所更新的行在子表中实际不存在或者存在:
update emp  set name=name  where dept_id=15;
或者update emp  set name=name  where dept_id=11;
 
Session0:此时加锁的信息都是如下:
SQL> @c:/showlock;
O_NAME          SID LOCK_TYPE            OBJECT_NAME         XIDUSN    XIDSLOT     XIDSQN
---------- ---------- -------------------- --------------- ---------- ---------- ----------
DAIMIN            142 Row Exclusive        EMP                     14         28        499
 
SQL> @c:/showalllock;
      SID TYPE        ID1        ID2 LOCK_TYPE               REQUEST      CTIME      BLOCK
---------- ---- ---------- ---------- -------------------- ---------- ---------- ----------
       142 TX       917532        499 Exclusive                     0         87          0
       142 TM        55612          0 Row Exclusive                0         87          0
分析:仅对子表中除外键以外的值进行更新,此时不需要牵涉到父表,所以此时的更新操作不需要对父表加任何的锁,只需要对子表加RX锁和TX锁。
 
实验3、
Session3:对子表进行删除操作,并且由删除条件查询出来的记录为空或者不为空时:
delete from emp where 1=0;
或者 delete from emp ;
 
Session0:此时加锁的信息都是如下:
SQL> @c:/showlock;
O_NAME            SID LOCK_TYPE            OBJECT_NAME         XIDUSN    XIDSLOT     XIDSQN
---------- ---------- -------------------- --------------- ---------- ---------- ----------
DAIMIN            142 Row share            DEPT                    17         28        502
DAIMIN            142 Row Exclusive        EMP                     17         28        502
 
SQL> @c:/showalllock;
   SID TYPE        ID1        ID2 LOCK_TYPE               REQUEST      CTIME      BLOCK
---------- ---- ---------- ---------- -------------------- ---------- ---------- ----------
       142 TM        55606          0 Row share                     0          6          0—DEPT表上的RS
       142 TX      1114140        502 Exclusive                      0          6          0 --EMP表上的TX
       142 TM        55612          0 Row Exclusive                 0          6          0 –EMP表上的RX
注:BLOCK=1 :表示锁被阻塞;BLOCK=0,表示未阻塞。
分析:对子表进行删除操作,也需要对父表加RS锁,猜想是因为需要验证被删除的这些记录中的外键值是否在父表还存在,所以需要在父表中加RS锁。然后对子表本身需要加RX锁和TX锁。
 
实验4、
Session4:更新子表的外键列:
update emp set dept_id= 12 where dept_id=11;
 
Session0:此时加锁的信息都是如下:
SQL> @c:/showlock;
O_NAME            SID LOCK_TYPE            OBJECT_NAME         XIDUSN    XIDSLOT     XIDSQN
---------- ---------- -------------------- --------------- ---------- ---------- ----------
DAIMIN            142 Row share            DEPT                    12         17        661
DAIMIN            142 Row Exclusive        EMP                     12         17        661
 
SQL> @c:/showalllock;
    SID TYPE        ID1        ID2 LOCK_TYPE               REQUEST      CTIME      BLOCK
---------- ---- ---------- ---------- -------------------- ---------- ---------- ----------
       142 TM        55606          0 Row share                     0          6          0
       142 TX       786449         661 Exclusive                     0          6          0
       142 TM        55612          0 Row Exclusive                 0          6          0
分析:和实验2比较,都是对子表进行更新操作,但是该实验是对外键值进行的更新,牵涉到父表,所以需要对父表DEPT加RS锁,子表EMP本身需要加RX锁和TX锁。
 
实验5、
Session5:对父表进行插入操作:
insert into dept values(15,'daimin');
 
Session0:此时加锁的信息都是如下:
SQL> @c:/showlock;
O_NAME            SID LOCK_TYPE            OBJECT_NAME         XIDUSN   XIDSLOT     XIDSQN
---------- ---------- -------------------- --------------- ---------- ---------- ----------
DAIMIN            142 Row Exclusive        DEPT                   13         36        671
DAIMIN            142 Row share            EMP                     13         36        671
 
SQL> @c:/showalllock;
      SID TYPE        ID1        ID2 LOCK_TYPE               REQUEST      CTIME      BLOCK
---------- ---- ---------- ---------- -------------------- ---------- ---------- ----------
       142 TM        55606          0 Row Exclusive                 0          6          0
       142 TX       852004         671 Exclusive                     0          3          0
       142 TM        55612          0 Row share                     0          6          0
分析:对父表进行插入操作,此时需要对父表DEPT加RX锁和TX锁,同时需要对子表EMP加RS锁。
 
实验6、
Session4:对父表DEPT进行更新操作,并且所更新的行在父表中实际不存在或者不存在:
update dept set name=name where dept_id=16;
或者 update dept set name=name where dept_id=12;
 
Session0:此时加锁的信息都是如下:
SQL> @c:/showlock;
O_NAME            SID LOCK_TYPE            OBJECT_NAME         XIDUSN    XIDSLOT     XIDSQN
---------- ---------- -------------------- --------------- ---------- ---------- ----------
DAIMIN            142 Row Exclusive        DEPT                    15         18        668
 
SQL> @c:/showalllock;
       SID TYPE        ID1        ID2 LOCK_TYPE               REQUEST      CTIME      BLOCK
---------- ---- ---------- ---------- -------------------- ---------- ---------- ----------
       142 TX       983058        668 Exclusive                     0          6          0
       142 TM        55606          0 Row Exclusive                 0          6          0
分析:仅对父表中的记录进行更新,此时不需要牵涉到子表,所以此时的更新操作不需要对子表加任何的锁,只需要对父表加RX锁和TX锁。
 
 
实验7、
Session7: 对父表DEPT进行删除操作,并且所更新的行在父表中实际不存在或者实际存在:
delete from dept where 1=0;
或者 delete from dept where dept_id=12;
 
Session0:此时加锁的信息都是如下:
SQL> @c:/showlock;
O_NAME            SID LOCK_TYPE            OBJECT_NAME         XIDUSN    XIDSLOT     XIDSQN
---------- ---------- -------------------- --------------- ---------- ---------- ----------
DAIMIN            142 Row Exclusive        DEPT                    15         28        671
DAIMIN            142 Row Exclusive        EMP                     15         28        671
 
SQL> @c:/showalllock;
     SID TYPE        ID1        ID2 LOCK_TYPE               REQUEST      CTIME      BLOCK
---------- ---- ---------- ---------- -------------------- ---------- ---------- ----------
       142 TM        55606          0 Row Exclusive                 0          6          0
       142 TX       983068        671 Exclusive                     0          6          0
       142 TM        55612          0 Row Exclusive                 0          6          0
分析:对父表DEPT与子表EMP都加了RS锁,并且由于是对DEPT父表进行删除行记录,所以为父表加了TX锁。有点疑问:我在创建子表时使用了ON DELETE CASCADE语句,为什么我在删除父表的记录时没有造成子表的相应记录删除呢?猜想应该在子表EMP上也应该有TX锁。
 
外键加索引情况,实验如下:
给表EMP的外键添加索引如下:
-- Create/Recreate indexes on the Foreign Key
create index EMP_DEPT_ID on EMP (DEPT_ID);
 
实验1、
Session1:对子表进行插入操作:
insert into emp values(2005,'dai',14);
 
session0:此时加锁的信息都是如下:
SQL> @c:/showlock;
O_NAME            SID LOCK_TYPE            OBJECT_NAME         XIDUSN    XIDSLOT     XIDSQN
---------- ---------- -------------------- --------------- ---------- ---------- ----------
DAIMIN            142 Row share            DEPT                    19         47        673
DAIMIN            142 Row Exclusive        EMP                    19         47        673
 
SQL> @c:/showalllock;
       SID TYPE        ID1        ID2 LOCK_TYPE               REQUEST      CTIME      BLOCK
---------- ---- ---------- ---------- -------------------- ---------- ---------- ----------
       142 TM        55606          0 Row share                     0          6          0
       142 TX      1245231        673 Exclusive                     0          6          0
       142 TM        55612          0 Row Exclusive                 0          6          0
分析:与外键没有加索引的情况中的实验1所加的锁一样,没有区别。
 
实验2、
Session2:对子表EMP进行更新操作,并且所更新的行在子表中实际不存在或者存在:
update emp  set name=name  where dept_id=15;
或者update emp  set name=name  where dept_id=11;
 
Session0:此时加锁的信息都是如下:
SQL> @c:/showlock;
O_NAME            SID LOCK_TYPE            OBJECT_NAME         XIDUSN    XIDSLOT     XIDSQN
---------- ---------- -------------------- --------------- ---------- ---------- ----------
DAIMIN            142 Row Exclusive        EMP                     13         13        676
 
SQL> @c:/showalllock;
       SID TYPE        ID1        ID2 LOCK_TYPE               REQUEST      CTIME      BLOCK
---------- ---- ---------- ---------- -------------------- ---------- ---------- ----------
       142 TX       851981        676 Exclusive                     0          6          0
       142 TM        55612          0 Row Exclusive                 0          6          0
分析:与外键没有加索引的情况中的实验2所加的锁一样,没有区别。
 
 
实验3、
Session3:对子表进行删除操作,并且由删除条件查询出来的记录为空或者不为空时:
delete from emp where 1=0;
或者 delete from emp ;
 
Session0:此时加锁的信息都是如下:
SQL> @c:/showlock;
O_NAME            SID LOCK_TYPE            OBJECT_NAME         XIDUSN    XIDSLOT     XIDSQN
---------- ---------- -------------------- --------------- ---------- ---------- ----------
DAIMIN            142 Row share            DEPT                    17         28        502
DAIMIN            142 Row Exclusive        EMP                     17         28        502
 
SQL> @c:/showalllock;
    SID TYPE        ID1        ID2 LOCK_TYPE               REQUEST      CTIME      BLOCK
---------- ---- ---------- ---------- -------------------- ---------- ---------- ----------
       142 TM        55606          0 Row share                     0          6          0—DEPT表上的RS
       142 TX      1114140        502 Exclusive                      0          6          0 --EMP表上的TX
       142 TM        55612          0 Row Exclusive                 0         6          0 –EMP表上的RX
注:BLOCK=1 :表示锁被阻塞;BLOCK=0,表示未阻塞。
分析:与外键没有加索引的情况中的实验3所加的锁一样,没有区别。
 
实验4、
Session4:更新子表的外键列:
update emp set dept_id= 12 where dept_id=11;
 
Session0:此时加锁的信息都是如下:
SQL> @c:/showlock;
O_NAME            SID LOCK_TYPE            OBJECT_NAME         XIDUSN    XIDSLOT     XIDSQN
---------- ---------- -------------------- --------------- ---------- ---------- ----------
DAIMIN            142 Row share            DEPT                    12         17        661
DAIMIN            142 Row Exclusive        EMP                     12         17        661
 
SQL> @c:/showalllock;
    SID TYPE        ID1        ID2 LOCK_TYPE               REQUEST      CTIME      BLOCK
---------- ---- ---------- ---------- -------------------- ---------- ---------- ----------
       142 TM        55606          0 Row share                     0          6          0
       142 TX       786449         661 Exclusive                     0          6          0
       142 TM        55612          0 Row Exclusive                 0          6          0
分析:与外键没有加索引的情况中的实验4所加的锁一样,没有区别。
 
实验5、
Session5:对父表进行插入操作:
insert into dept values(15,'daimin');
 
Session0:此时加锁的信息都是如下:
SQL> @c:/showlock;
O_NAME            SID LOCK_TYPE            OBJECT_NAME         XIDUSN    XIDSLOT     XIDSQN
---------- ---------- -------------------- --------------- ---------- ---------- ----------
DAIMIN            142 Row Exclusive        DEPT                   13         36        671
DAIMIN            142 Row share            EMP                     13         36        671
 
SQL> @c:/showalllock;
      SID TYPE        ID1        ID2 LOCK_TYPE               REQUEST      CTIME      BLOCK
---------- ---- ---------- ---------- -------------------- ---------- ---------- ----------
       142 TM        55606          0 Row Exclusive                 0          6          0
       142 TX       852004         671 Exclusive                     0          3          0
       142 TM        55612          0 Row share                     0          6          0
分析:与外键没有加索引的情况中的实验5所加的锁一样,没有区别。
 
实验6、
Session4:对父表DEPT进行更新操作,并且所更新的行在父表中实际不存在或者不存在:
update dept set name=name where dept_id=16;
或者 update dept set name=name where dept_id=12;
 
Session0:此时加锁的信息都是如下:
SQL> @c:/showlock;
O_NAME            SID LOCK_TYPE            OBJECT_NAME         XIDUSN    XIDSLOT     XIDSQN
---------- ---------- -------------------- --------------- ---------- ---------- ----------
DAIMIN            142 Row Exclusive        DEPT                    15         18        668
 
SQL> @c:/showalllock;
       SID TYPE        ID1        ID2 LOCK_TYPE               REQUEST      CTIME      BLOCK
---------- ---- ---------- ---------- -------------------- ---------- ---------- ----------
       142 TX       983058        668 Exclusive                     0          6          0
       142 TM        55606          0 Row Exclusive                 0          6          0
分析:与外键没有加索引的情况中的实验6所加的锁一样,没有区别。
 
实验7
Session7: 对父表DEPT进行删除操作,并且所更新的行在父表中实际不存在:
delete from dept where 1=0;
 
Session0:此时加锁的信息都是如下:
 
SQL> @c:/showlock;
O_NAME            SID LOCK_TYPE            OBJECT_NAME         XIDUSN    XIDSLOT     XIDSQN
---------- ---------- -------------------- --------------- ---------- ---------- ----------
DAIMIN            142 Row Exclusive        DEPT                    13         38        676
DAIMIN            142 Row share            EMP                     13         38        676
 
SQL> @c:/showalllock;
     SID TYPE        ID1        ID2 LOCK_TYPE               REQUEST      CTIME      BLOCK
---------- ---- ---------- ---------- -------------------- ---------- ---------- ----------
       142 TM        55606          0 Row Exclusive                 0          5          0
       142 TX       852006        676 Exclusive                     0          5          0
       142 TM        55612          0 Row share                    0          5          0
分析:猜测可能是由于在父表中根本没有查找到记录,所以就在子表中不需要对子表EMP行进行删除,所以对子表EMP加的是RS锁。这里和外键没有加索引的情况中的实验7所加的锁一样有锁不一样,在子表中所加的锁是RS锁,而不是RX锁。
 
实验8、
Session7: 对父表DEPT进行删除操作,并且所更新的行在父表中实际存在:
 delete from dept where dept_id=12;
 
Session0:此时加锁的信息都是如下:
SQL> @c:/showlock;
O_NAME            SID LOCK_TYPE            OBJECT_NAME         XIDUSN    XIDSLOT     XIDSQN
---------- ---------- -------------------- --------------- ---------- ---------- ----------
DAIMIN            142 Row Exclusive        DEPT                    15         28        671
DAIMIN            142 Row Exclusive        EMP                     15         28        671
 
SQL> @c:/showalllock;
     SID TYPE        ID1        ID2 LOCK_TYPE               REQUEST      CTIME      BLOCK
---------- ---- ---------- ---------- -------------------- ---------- ---------- ----------
       142 TM        55606          0 Row Exclusive                 0          6          0
       142 TX       983068        671 Exclusive                     0          6          0
       142 TM        55612          0 Row Exclusive                 0          6          0
分析:与外键没有加索引的情况中的实验7所加的锁一样,没有区别。
### 索引的关系及影响 #### 1. 约束的定义 种用于维护表间关系的约束,确保引用完整性。当个表中的列引用另个表的主时,该列被称为。例如,在 `students` 表中定义 `class_id` 作为,关联到 `classes` 表的 `id` 列[^4]。 #### 2. 索引中的作用 在数据库中,定义约束时,并不会自动创建索引。然而,为了提高查询性能维护引用完整性,通常需要手动为列创建索引。如果没有索引,执行涉及的操作(如删除或更新父表中的记录)可能会导致性能下降,因为数据库需要扫描整个子表来验证引用完整性[^2]。 #### 3. 索引的关系 - **不依赖于索引**:约束本身的功能是确保数据致性,而不需要依赖于索引的存在。 - **索引提升性能**:虽然约束可以独立工作,但为了速查询维护操作,建议在列上创建索引。例如: ```sql CREATE INDEX idx_class_id ON students(class_id); ``` - **约束的性能问题**:如果列没有索引,执行删除或更新操作时可能导致全表扫描,从而降低性能。因此,即使数据库强制要求,也应考虑为添加索引[^2]。 #### 4. 索引的影响 - **性能影响**:在列上创建索引可以显著提高涉及的操作性能,尤其是在大规模数据集上。 - **存储开销**:索引会增存储空间的需求,因此需要权衡性能存储成本。 - **维护开销**:索引需要额的维护操作(如插入、删除更新时的索引更新),这可能对列的写操作性能产生定影响。 #### 5. 示例代码 以下是个示例,展示如何在列上创建索引以优化性能: ```sql -- 创建父表 CREATE TABLE classes ( id INT PRIMARY KEY, name VARCHAR(100) ); -- 创建子表并定义 CREATE TABLE students ( id INT PRIMARY KEY, name VARCHAR(100), class_id INT, FOREIGN KEY (class_id) REFERENCES classes(id) ); -- 为列创建索引 CREATE INDEX idx_class_id ON students(class_id); ``` --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值