Oracle删除性能

发布于 2024-12-12 04:03:25 字数 628 浏览 0 评论 0原文

假设我有两个表:

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

夏日落 2024-12-19 04:03:25

这是一个测试。我的 PARENT 表有 100000 行。针对空 CHILD 表(在 PARENT_ID 上有索引)删除需要很长时间:

SQL> set timing on
SQL> delete from parent;

100000 rows deleted.

Elapsed: 00:00:07.24
SQL> 

让我们向 CHILD 中插入一些行。这将为 PARENT 中的每一行生成一行

SQL> insert into child
  2  select level, level from dual
  3  connect by level <= 100000;


100000 rows created.

Elapsed: 00:00:02.21
SQL> 

如果我们现在从父级中删除,它会立即失败。

SQL> delete from parent;
delete from parent
*
ERROR at line 1:
ORA-02292: integrity constraint (APC.CHILD_FK1) violated - child record found


Elapsed: 00:00:00.14
SQL> 

然而,如果我们让 CHILD 中的每条记录都指向 PARENT 中的一条记录,则需要更长的时间……

SQL> update child set parent_id=99999;

100000 rows updated.

Elapsed: 00:00:09.65
SQL> commit;

SQL> delete from parent;
delete from parent
*
ERROR at line 1:
ORA-02292: integrity constraint (APC.CHILD_FK1) violated - child record found


Elapsed: 00:00:07.32

众所周知,挂钟计时非常不可靠,但看起来时间量大致相同。碰巧的是,删除没有外键依赖项的父表的时间大致相同:

SQL> drop table child;

Table dropped.

Elapsed: 00:00:02.29
SQL> delete from parent;

100000 rows deleted.

Elapsed: 00:00:06.54
SQL> 

因此,基本上,检查外键约束的开销很小或没有开销

有一个附带条件:这是正确的提供外键列已建立索引。我删除了 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:

SQL> set timing on
SQL> delete from parent;

100000 rows deleted.

Elapsed: 00:00:07.24
SQL> 

Let's insert some rows into CHILD. This will generate one row for every row in PARENT

SQL> insert into child
  2  select level, level from dual
  3  connect by level <= 100000;


100000 rows created.

Elapsed: 00:00:02.21
SQL> 

If we delete from parent now, it fails instantly.

SQL> delete from parent;
delete from parent
*
ERROR at line 1:
ORA-02292: integrity constraint (APC.CHILD_FK1) violated - child record found


Elapsed: 00:00:00.14
SQL> 

Whereas, if we have every record in CHILD point to just one record in PARENT it takes a bit longer...

SQL> update child set parent_id=99999;

100000 rows updated.

Elapsed: 00:00:09.65
SQL> commit;

SQL> delete from parent;
delete from parent
*
ERROR at line 1:
ORA-02292: integrity constraint (APC.CHILD_FK1) violated - child record found


Elapsed: 00:00:07.32

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:

SQL> drop table child;

Table dropped.

Elapsed: 00:00:02.29
SQL> delete from parent;

100000 rows deleted.

Elapsed: 00:00:06.54
SQL> 

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.

我最亲爱的 2024-12-19 04:03:25

因为你的子表在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 ...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文