生产库建主键的正确姿势:避免锁表的那些坑


前几天在生产环境踩了个坑:给一张大表加主键,结果查询语句直接hang住了。排查过程简直让人怀疑人生,最后发现是锁模式冲突导致的。

复现现场

Session1(运维操作):

-- 先建索引
create index pk_test on test (ID);
-- 再加主键
alter table test add constraint pk_test primary key (ID) using index;

Session2(业务查询):

select * from test;

结果:Session2直接卡死

深入分析:锁模式冲突

通过dump共享池(alter system dump shared_pool),发现表的handler上存在:

  • X模式的LOCK(排他锁)
  • X模式的PIN(排他PIN)

此时业务查询需要获取S模式的LOCK(共享锁),与DDL操作的X模式LOCK发生互斥,导致查询阻塞。

Oracle中DDL操作(如ADD CONSTRAINT)需要获取表级排他锁(X),而查询需要共享锁(S),两者不兼容。

最佳实践:如何优雅地加主键?

错误方式(会锁表):

直接执行:

alter table test add constraint pk_test primary key (ID);

Oracle会自动创建唯一索引,但整个过程会长时间持有X锁,阻塞查询。

正确姿势(分三步走):

步骤1:提前建唯一索引(非阻塞)

create unique index pk_test on test(ID) online;
  • 使用online关键字:不锁表(允许DML操作)
  • 确保字段有非空约束(主键要求):
alter table test modify (ID not null);

步骤2:验证索引和数据

-- 检查索引状态
select status from user_indexes where index_name='PK_TEST';
-- 检查数据唯一性
select ID, count(*) from test group by ID having count(*)>1;

步骤3:关联主键约束(秒级完成)

alter table test add constraint pk_test primary key (ID) using index pk_test;

此时只是元数据操作,无需重新扫描表,几乎瞬间完成

避坑指南:生产环境操作建议

操作阶段命令锁模式影响
建唯一索引create unique index online不阻塞查询/DML
加非空约束alter table modify not null行级锁快速完成
加主键约束alter table add constraint元数据锁毫秒级完成

关键检查项:

  1. 字段非空:主键列必须有非空约束(否则会报错ORA-02431)。
  2. 数据唯一性:提前检查是否有重复值(否则加主键会失败)。
  3. 索引状态:确保索引状态为VALID(不可用索引会导致主键失效)。

“大表加主键,先online建唯一索引,再秒级绑定约束,千万别让DDL直接上桌!”


发表评论

您的邮箱地址不会被公开。 必填项已用 * 标注

滚动至顶部