Oracle删除性能
假设我有两个表:
create table parent (
id number not null,
constraint parent_pk primary key(id),
)
create table child (
id number not null,
parent_id number not null,
constraint child_pk primary key(id),
constraint child_fk1 foreign key(parent_id)
references parent(id)
)
父表很大,比如 300 万条记录。现在我运行删除语句:
delete from parent; //even without where clause
您能否解释一下执行此语句时实际发生的情况?哪里没有指定“ON DELETE CASCADE”选项,据我了解,这意味着如果子表包含对父 id 的引用,则从父表中删除应该失败。因此,这意味着在从父表中删除行之前,Oracle 应检查是否存在任何子记录。但这确实非常慢——它是逐行删除。
我说得对吗?如果没有,请解释Oracle在从父表删除时如何工作,并检查子表中是否没有留下孤儿?
Say I have two tables:
create table parent (
id number not null,
constraint parent_pk primary key(id),
)
create table child (
id number not null,
parent_id number not null,
constraint child_pk primary key(id),
constraint child_fk1 foreign key(parent_id)
references parent(id)
)
The parent table is big, say, 3 millions records. Now I run delete statement:
delete from parent; //even without where clause
Could you please explain what actually happens when this statement is executed? Where is no "ON DELETE CASCADE" option specified, as far as I understand it means that delete from parent table should fail if the child table contains references to parent id. So this means that before deleting the row from parent table Oracle should check if any child records exists. But this is really extremely slow - it's row-by-row delete.
Am I correct? If not, please explain how Oracle works when deleting from parent table and check whether there are no orphans left in child table?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
这是一个测试。我的 PARENT 表有 100000 行。针对空 CHILD 表(在 PARENT_ID 上有索引)删除需要很长时间:
让我们向 CHILD 中插入一些行。这将为 PARENT 中的每一行生成一行
如果我们现在从父级中删除,它会立即失败。
然而,如果我们让 CHILD 中的每条记录都指向 PARENT 中的一条记录,则需要更长的时间……
众所周知,挂钟计时非常不可靠,但看起来时间量大致相同。碰巧的是,删除没有外键依赖项的父表的时间大致相同:
因此,基本上,检查外键约束的开销很小或没有开销
有一个附带条件:这是正确的提供外键列已建立索引。我删除了 CHILD_FK1_I 索引,在我输入此响应(即大约十分钟)的时间内,
从父级删除
语句仍未完成。Here's a test. My PARENT table has 100000 rows. Against an empty CHILD table (with an index on PARENT_ID) deletion takes this long:
Let's insert some rows into CHILD. This will generate one row for every row in PARENT
If we delete from parent now, it fails instantly.
Whereas, if we have every record in CHILD point to just one record in PARENT it takes a bit longer...
Wallclock timings are notoriously unreliable, but that looks like roughly the same amount of time. And as it happens, the time to delete the PARENT table without foreign key dependencies is in the same ballpark:
So, basically, there is little or no overhead to check the foreign key constraint
There is a proviso: this is true providing the foreign key column is indexed. I dropped the CHILD_FK1_I index, and the
delete from parent
statement still hasn't finished in the time it's taken me to type up this response i.e. about ten minutes.因为你的子表在parent_id上没有索引,所以每次需要检查子表是否存在时,oracle都被迫进行完整扫描。当您计划对多个进程执行此操作时,缺少此索引可能会引发的另一个问题是争用。如果没有对parent_id建立索引,子表将获得表锁,通常只有一行被锁定。
除此之外,向数据库发出删除行的命令是最糟糕的执行命令。如果你看看水下发生的事情(撤消、重做等),你会发现一切都发生得那么快,真是令人惊讶......
Because your child table has no index on parent_id, oracle is forced to do a full scan every time it needs to check for existence of children. Another problem that the lack of this index could raise when you plan to do this with multiple processes is contention. Without the parent_id being indexed, the child table will get a table lock, where normally only a row would be locked.
Besides that, giving the database the order to delete a row is the worst possible command to execute. If you look to what happens underwater (undo, redo etc.) it is amazing that it all goes that quick ...