【问题标题】:Strategy to improve Oracle DELETE performance提高 Oracle DELETE 性能的策略
【发布时间】:2015-08-31 14:59:01
【问题描述】:

我们的 Oracle 11g 安装开始变得越来越大。该数据库是在集群上运行的并行优化系统的后端。该过程的输入与优化步骤的输出一起包含在数据库中。输入包括死记硬背的配置数据和一些二进制文件(使用 11g 的 SecureFiles)。输出包括当前存储在 DB 中的 1D、2D、3D 和 4D 数据。

数据库结构:

/* Metadata tables */
Case(CaseId, DeleteFlag, ...) On Delete Cascade CaseId
OptimizationRun(OptId, CaseId, ...) On Delete Cascade OptId
OptimizationStep(StepId, OptId, ...) On Delete Cascade StepId

/* Data tables */
Files(FileId, CaseId, Blob) /* deletes are near instantateous here */

/* Data per run */
OnedDataX(OptId, ...)
TwoDDataY1(OptId, ...) /* packed representation of a 1D slice */

/* Data not only per run, but per step */
TwoDDataY2(StepId, ...)  /* packed representation of a 1D slice */
ThreeDDataZ(StepId, ...) /* packed representation of a 2D slice */
FourDDataZ(StepId, ...)  /* packed representation of a 3D slice */
/* ... About 10 or so of these tables exist */

每天都会出现一个收割者脚本,并使用DeleteFlag = 1 查找案例并继续使用DELETE FROM Case WHERE DeleteFlag = 1,从而允许级联继续进行。

这种策略非常适合读/写,但现在在我们想要清除数据时超出了我们的能力!问题是删除一个案例大约需要 20-40 分钟,具体取决于大小,并且经常会使我们的存档空间超载。该产品的下一个主要版本将采用“从头开始”的方法来解决问题。下一个次要版本需要保持在数据库中存储的数据范围内。

因此,对于次要版本,我们需要一种可以提高删除性能并且最多需要对数据库进行适度更改的方法。

  1. REF 分区,但问题是如何?我很想在Case 上做 INTERVAL,在其余部分上做 REF,but that isn't supported。有没有办法通过触发器手动将OptimizationRun 分区为CaseId
  2. 禁用归档/重做日志以进行删除?找不到与此相关的提示。甚至不确定它是否可行。
  3. 截断?这可能需要一些复杂的表格设置。但也许我没有考虑所有的选择。 (每个答案,受打击)

为了帮助说明问题,每个案例的相关数据范围从 15MiB 到 1.5GiB,行数从 20k 到 2M。

更新:当前数据库大小约为 1.5TB。

【问题讨论】:

  • 一个设计问题:如果依赖树看起来是Case -> OptimizationRun -> OptimizationStep,为什么有些表会同时携带这两者?如果使用DELETE CASCADE,您将对那些 12/13 表运行两次删除;一次用于 OptID 键,再次用于 StepID 键!如果其中一个外键没有被索引,性能会更差!
  • @Adam Musch:这是一个错误,这些表上只有 1 个键。谢谢你接听!

标签: oracle oracle11g


【解决方案1】:

对于数据库而言,删除数据是一项艰巨的工作。它必须先创建图像、更新索引、写入重做日志和删除数据。这是一个缓慢的过程。如果您可以有一个窗口来执行此任务,最简单和最快的方法是构建包含所需数据的新表。删除旧表并重命名新表。 这需要一些设置工作,这很明显,但很可能做到。 不那么激烈的一步是在删除发生之前删除索引。我的投票将投给 CTAS(创建表格作为选择来源)并构建新表格。 一个好的分区模式肯定会有所帮助,也许在下一个版本中,Oracle 可以结合区间和参考分区。要是有就太好了。

禁用日志记录....不能用于删除,但 CTAS 可以使用 nologging。准备好后进行备份,并确保将数据文件传输到备用数据库(如果有的话)。

【讨论】:

  • 我想我对 CTAS 方法的问题是,只要我们删除 1 个案例,我们就会“复制” 50-100GB 中的 49-99GB。此外,如果我们一开始就几乎满了表空间,我认为这不会很好。
  • 是的,这是真的。根据存储的配置方式,可以在半小时内完成。如果数据不经常修改,您可以考虑在 CTAS 期间压缩表。在这种情况下,您很可能会赢得空间。另一种选择是安排不断删除数据的删除作业。最聪明的是不使用级联,而是开始从子表删除到父表。外键是否被索引?
  • 是的,FK 已编入索引。然而,我们没有看到手动删除有任何改进。
  • 触发器是否在响应时间中起作用?他们真的可以扼杀性能。删除使用什么计划?在从子项开始的手动批量删除中,我希望性能比回退到级联选项更好。是否有很多索引?你能放下它们吗?
  • 有触发器,但我不相信它们会在删除时执行。你所说的“批量删除”是指DELETE FROM table WHERE id = ...吗?
【解决方案2】:

只是一些想法:

  1. 我假设您对所有外键都有索引。 ON DELETE CASCADE 将持有行级锁,直到 Case 删除完成,并且没有索引将持有表锁,我相信当然会超级慢

  2. 您有任何延迟限制吗?这很可能会减慢 Oracle 通过各种表删除进行级联的速度

  3. 您是否尝试过对所有受影响的表分别进行删除(而不是依赖于删除级联)?没那么容易,但您可能会感到惊讶。

编辑:

再想一想。您可以考虑对 Case 表进行 SOFT 删除,这意味着您有一个状态字段,它将告诉您的应用程序是否应该考虑该 Case。该标志可能有许多不同的值,但可能“A”表示活动,“I”表示不活动。假设您始终使用 Case 作为连接其他表的驱动/主表,您可以避免一起进行 HARD 删除(如果您愿意,偶尔可以按照任何时间表进行清理)。应用程序当然需要知道这个标志,并且你会被绑定到重新加入 Case 表。可能适合也可能不适合您的情况...

【讨论】:

  • 我们必须进行硬删除以释放空间。它已经使用 DeleteFlag 作为软删除。单独的删除似乎并没有加快任何速度。没有延迟约束。
  • 现在磁盘很便宜。我会说您的级联删除更昂贵。此外,删除不会重置高水位标记,因此您未来的插入将高于该 HWM,并且不会像您想象的那样真正节省空间。您需要执行截断或 CTAS 才能真正释放空间。
  • 理论上磁盘很便宜;实际上,将存储添加到我们的数据库可能需要 1-2 个月。切换到分区策略是否可以让我们更好地管理空间?
  • 好吧,截断分区会释放空间,而删除数百万行则不会。同样,不确定您的痛点是否准确。如果它确实是空间,那么执行删除将无济于事,最重要的是,您会通过生成所有这些日志来制造更大的问题。但也许我在这里误解了你
  • 当删除一行从而释放块内的空间时,Oracle 可能会将该空闲空间重新用于后续插入。根据更新模式,您可能根本不需要回收任何空间,因为您可能会插入/删除相同数量的存储空间。此外,对于索引访问,高水位线并不重要。
【解决方案3】:

CASCADE DELETE 在内部缓慢运行,呃,逐行运行。

一些选项:

  1. 让您的清除作业将所有要清除的案例快照到带有 CTAS 的临时表中。然后让您的清除作业在该表上循环,分别删除每个案例(及其子案例)。这可能会令人不快,尤其是当您遇到数百万个后代行时。最近,我们不得不在 [business redacted] 更改其中一个流程,以确定哪些最终父级的子级计数会出现问题,然后在删除有问题的子表时使用 rownum 限制器。它并不快,但至少从撤消/重做管理的角度来看,通过设置任何事务的大小上限更安全。

  2. 如果您使用CASCADE DELETE 是为了方便,则始终不能这样做。您必须编写一个更复杂的清除例程,从“自下而上”的依赖关系树中删除。

  3. 1234563软删除时移动行会产生撤消/重做成本,但是当最终清除时,它将截断 DeleteFlag = 1 的分区,仅此而已。
  4. 添加存储相对便宜。如果有基于日期的保留选项,请使用它,然后让软删除选项隐藏应用程序前端的数据。这很不优雅,但是CASCADE DELETE 也是如此。

【讨论】:

  • 1.我们现在正在生产中这样做,受到rownum的限制。 2. 自底向上不快也不慢。我不知道为什么。 3. 启用行移动会造成多大的性能损失? 4.“便宜”的定义是什么。如果我想增加空间,无论价格如何,都需要 1-2 个月,这只是业务的现实。
  • 使用行移动的性能成本将取决于实际插入和删除那么多数据的顺序。潜在的优势是删除成本将被“纳入”系统的操作。对于删除与删除或截断,总是现在付款或以后付款。
【解决方案4】:

不建议用于实时数据库。

  1. 我禁用了引用删除缓慢的表的外键约束。
  2. 我执行了删除
  3. 再次启用外键。

【讨论】:

  • 在生产数据库中这样做并不安全,它可能适用于小型项目或个人项目。
【解决方案5】:

使用 Enterprise Manager 创建 AWR 报告并通过 statspack analyzer 运行它,这将为您提供有关系统瓶颈的详细说明。 AWR 报告是一个文本文件,其中包含有关数据库在特定时间内做了什么以及花费了多长时间的各种数据......那个 statspack 分析器是一种自动 DBA,告诉你该做什么。

在 Statspack Analyzer 告诉您它们可能有用并且您有一些空闲磁盘可用于分配 I/O 之前,请忘记分区。

不要考虑截断。它强制提交...

顺便说一句,我不隶属于 Statspack Analyzer,但我认为这对于 Oracle 来说是一种非常可行的通用调优方法,尤其是在没有 DBA 的情况下。

【讨论】:

  • 1.直接来自 oracle 文档:INTERVAL 分区不能与 REF 分区一起使用。我指的不是所有分区,只是那个组合。 2. 不记录不影响删除,我不想因为写入而丢失记录。 3. 听起来不错。
  • 对于那个大小的数据库,我肯定会先做一个 statspack 报告。
  • 我们一直在使用精确的 i3 对其进行分析,并了解到我们的删除是瓶颈。
  • 我相信 statspack 报告会超越 i3。为了调整您的删除,您必须首先了解它们导致了多少物理 I/O 以及 I/O 如何在您的分区中分布。
  • 0 个分区,很容易找到分布 :)
猜你喜欢
  • 2010-10-09
  • 1970-01-01
  • 2020-09-26
  • 2013-03-28
  • 1970-01-01
  • 2013-01-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多