删除NOTNULL约束时触发全表扫描,如何规避该性能问题?
避免删除NOT NULL约束时的全表扫描
这个场景我太熟悉了——2500万条记录的大表,删个NOT NULL约束居然跑全表扫描,等得人抓狂!其实Oracle默认这么做,是因为它会隐式检查表中所有行是否符合约束修改后的状态(虽然你是要去掉约束,但老版本或某些场景下它还是会扫一遍)。不过别担心,有两个简单的办法能跳过这个扫描,直接修改元数据:
方法1:使用NOVALIDATE子句修改列
NOT NULL约束本质是列级的CHECK约束,你可以用MODIFY COLUMN搭配NOVALIDATE来跳过全表验证。这个操作只会修改数据字典里的约束状态,完全不会碰表数据,速度快到离谱。
执行的SQL语句如下:
ALTER TABLE your_table_name MODIFY (your_column_name NULL NOVALIDATE);
- 这里的
NOVALIDATE告诉Oracle:不要检查现有数据,只更新约束定义。因为你本来就是要允许该列存NULL,所以有没有旧的NULL值根本不影响,完全没必要扫全表。
方法2:显式删除约束(如果是命名约束)
如果你的NOT NULL约束是有显式名称的(比如建表时用CONSTRAINT nn_col CHECK (col IS NOT NULL)),那可以直接删除约束并加上NOVALIDATE:
ALTER TABLE your_table_name DROP CONSTRAINT constraint_name NOVALIDATE;
不过这种情况不如方法1常用,因为大多数NOT NULL都是隐式的列级约束。
注意事项
- 用
NOVALIDATE之后,如果你后续想重新给该列加NOT NULL约束,默认还是会扫全表检查所有行有没有NULL。如果那时候你只想约束新数据、不管旧数据,可以用ALTER TABLE ... MODIFY (col NOT NULL NOVALIDATE);。 - 这个方法适用于所有大表场景,完全不会锁表太久(只是元数据操作),对业务影响极小。
内容的提问来源于stack exchange,提问作者rk_cpa




