【问题标题】:ORACLE 11g SET COLUMN NULL for specific Partition of large tableORACLE 11g SET COLUMN NULL 用于大表的特定分区
【发布时间】:2013-08-26 15:56:05
【问题描述】:

我有一个 Composite-List-List 分区表,它有 19 列和大约 4 亿行。每周在此表中插入一次新数据,在插入之前,我需要将特定分区的 2 列的值设置为 null。

明显的方法如下所示,其中 COLUMN_1 是分区标准:

UPDATE BLABLA_TABLE 
SET COLUMN_18 = NULL, SET COLUMN_19 = NULL 
WHERE COLUMN_1 IN (VALUE1, VALUE2…)

当然这会非常慢。

我的第二个想法是对我需要将这两列设置为 null 的每个分区使用 CTAS,然后使用 EXCHANGE PARTITION 更新我的大表中的数据。不幸的是,这行不通,因为它是一个复合分区。

我可以对子分区使用相同的方法,但是我必须使用 CATS 大约 8000 次,然后每周删除这些表。我猜这不会通过即将到来的代码审查。

可能有人有另一个想法如何有效地解决这个问题?

PS:我使用 ORACLE 11g 作为数据库。 PPS:对不起我的英语不好……..

【问题讨论】:

  • 要更新多少行?你会更新整个子分区吗?更新前这些列中的数据有多大(估计撤消日志)?
  • 我将分别更新整个分区,该分区中每个子分区的所有行不为空(大约 90%)。将更新大约 120.000.000 万行。 COLUMN_18 定义为 NUMBER(10,4),COLUMN_19 定义为 NUMBER(10)。

标签: sql oracle oracle11g


【解决方案1】:

您已排除通过 DDL(切换分区)进行更新,因此我们只考虑 DML。

我不认为对表进行如此严重分区的更新实际上并没有那么糟糕。您可以轻松地将更新拆分为 8k 小更新(每个小分区):

UPDATE BLABLA_TABLE SUBPARTITION (partition1) SET COLUMN_18 = NULL...

每个子分区平均包含 15k 行要更新,因此更新量相对较小。

虽然它仍然代表着大量的工作,但它应该很容易设置为并行运行,希望在数据库活动非常少的几个小时内。此外,如果其中一个更新失败(行被锁定?),单个更新很容易重新启动,而 120M 的更新在出现错误时需要很长时间才能回滚。

【讨论】:

  • 这就是答案......如果你并行化它应该没问题。
  • 我同意。使用子分区修剪将其分解为许多小作业是明智的选择。但显然每周更新 1.2 亿行的要求很糟糕。
  • 每周更新 1.2 亿行确实很糟糕。但情况是我有很大的非规范化和历史化表(QlikView 想要这样,或者至少我们的 QlikView 开发人员......)并且每周都有新数据加入其中。问题:只有两列必须具有最新值。所以我必须以某种方式将这两列的所有旧值设置为空。我将使用并行更新,谢谢。
【解决方案2】:

如果我要更新表中几乎 90% 的行,我会检查仅插入到另一个具有相同结构的表的可行性/持续时间(更少重做、没有行链接/迁移、通过直接插入绕过缓存等等。首先删除索引和触发器。排除列以使其在目标表中为空),重命名表以“交换”它们,重建索引和触发器,然后删除旧表。

根据我在数据仓库方面的经验,直接插入比更新/删除要好。需要更多步骤,但总体而言时间更短。我同意,当您必须处理大部分表时,分区交换说起来容易做起来难,只是让 ETL 开发人员更复杂(逻辑/算法绑定到物理层中的内容),我们没有遇到需要做到目前为止的分区交换。

我还将这个表隔离在它自己的表空间中,然后在这两个表空间之间交替存储(从第一个删除表插入到第二个删除表,下一次运行反之亦然,调整空表空间的大小以回收空间)。

【讨论】:

  • 为了进一步解释,更新/删除的问题是块从存储到内存来回移动,并在过程中产生大量的重做/撤消,这是额外的 I/O。最好跳过由实例通过直接读取和直接写入完成的“内务处理”(因此这两个表空间,如果它们在不同的 I/O/网络路径上更好,因此它是单向流量)。需要更多存储空间,但如果它在更短的时间内完成并让每个人的生活更轻松,只需购买额外的存储空间。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-18
  • 1970-01-01
  • 2013-11-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-12-25
相关资源
最近更新 更多