更新所有行


12

我想知道以最有效的方式针对单个列更新超大型Oracle表中的每一行。例如:

update mytable set mycolumn=null;

要么:

update mytable set mycolumn=42;

我的知识可能很过时。我要做的是更改表以删除列。然后,我更改表以添加具有我要使用的新值的默认值的列。然后,我更改表以删除该列的默认值。我发现这比运行更新要快得多,但是我觉得有更好的方法。


据我了解,添加一个默认的新的非null列是Oracle中仅元数据的更改。我怀疑他们是否会优化“将所有行更新为相同的值”的情况。这是您的常用操作吗?
马丁·史密斯

1
只需尝试两种方法并为其计时。是什么阻止您这样做?注意,您必须以相同的结果而不是不同的结果结束!否则,比较无效。
tvCa

@tvCa我已经尝试过两种方式。如果我只是进行更新,它将运行约两个小时,然后我将其杀死。如果我删除一列,只需几秒钟。添加没有默认值的列(该列为空)仅需要几秒钟。添加具有默认值的列大约需要30分钟。因此,例如,如果我想将列中的所有值都设置为“某些值”,那么我目前要删除并添加该列。我只想知道是否有更快的方法。
kainaw

2
您正在使用11gR2吗?@MartinSmith是正确的。请参见此处的描述,以了解如何将带有DEFAULT的新列添加为NOT NULL比将其添加为NULL快得多,这将强制更新表中的所有行(就像发出UPDATE语句一样)。我看到的问题是后来删除了DEFAULT值,因为性能提高来自于将DEFAULT存储在字典中。此时,您还必须处理NOT NULL约束。
ansible

Answers:


2

在进行此批量更新时,很大程度上取决于针对此表进行的其他活动。我希望您拥有某种测试环境,可以在其中运行您想做的事的一些样本,并了解哪种方法最好。我会尝试:

  1. 跑单update table set column_name = blah;
  2. 创建一个plSql循环以选择表中的所有主键并循环浏览它们,updating the column=blah并提交每个X更新(也许是10000)。您可以通过复制代码并使它复制成为并行的主键的单独部分来并行化此代码。

对于在OLTP系统中非常活跃使用的表,我们有一个非常相似的问题,我们能够对其进行5倍并行化,并且在没有用户锁定的情况下对每10000次提交的100+ MM行表没有用户锁定的影响。您没有说如何您的表太大或正在运行哪种应用程序,但是这种解决方案可能适合您。


0

快速而言UPDATE,请确保您没有触发任何触发器。

SELECT trigger_name, status FROM user_triggers WHERE table_name = 'MYTABLE';

ALTER TABLE mytable DISABLE ALL TRIGGERS;

完成后,请确保仅重新启用所需的功能。

ALTER TRIGGER mytrigger ENABLE;

您可能还会遇到索引维护的开销。尝试分别重建索引。为此,pappes的答案应该会有所帮助:https ://stackoverflow.com/questions/129046/disable-and-later-enable-all-table-indexes-in-oracle

我在这里重复pappes的答案以供参考。(请注意,此SPOOL命令对您的平台和环境进行了假设。)

set pagesize 0    
alter session set skip_unusable_indexes = true;
spool c:\temp\disable_indexes.sql
select 'alter index ' || u.index_name || ' unusable;' from user_indexes u;
spool off
@c:\temp\disable_indexes.sql

导入...

select 'alter index ' || u.index_name || ' rebuild online;'
  from user_indexes u;

-1

删除索引。更新列。返回索引。但是如果该列的所有行都包含一个相同的值,则可以删除索引。


-2

如果没有空间限制,则可以创建一个新表,该表与添加了新列的表相同,然后删除旧表:

create new_table as
select old_table.*, (with or without default_Value) as new_column
from old_table;

1
这样会更有效吗?为什么?如果有引用现有表的FK,该怎么办?
ypercubeᵀᴹ

是的,您可以在其他样本表上尝试一下,然后自己查看结果。如果有FK,我不太清楚,但是如果有效率,您可以禁用并启用它们。
E_Salamon

-3

尝试多个更新/提交序列。在没有提交的情况下插入/更新/删除太多的行会导致大量的IO负载。知道块大小,记录大小和内容,可以进行相当优化。

对于删除表上的整个数据,truncate table x它比更好delete from x。清除也会增加另一个过程的工作量。

编辑:您可以使用inmemory选项,以列格式将表加载到内存中,然后进行更新。它确实取决于数据库的关系和结构。看到这篇文章


3
他们想更新表的一列。我不知道怎样truncatedelete将是任何帮助。
ypercubeᵀᴹ

@ypercube我刚刚解释了没有提交的多个数据操作如何导致不必要的IO负载;是update或其他OLTP。
狡猾的

3
您能解释一下频繁提交会减少 I / O吗?他们不会因为检查点而增加 I / O吗?
mustaccio

3
您使用非常规术语(“ tx期刊”,“更改会话”)有点令人困惑。无论您使用多个短期交易还是一个大型交易,生成的重做记录的总数量将相同。I / O操作仅在将重做日志缓冲区写入磁盘时才发生(暂时不保留缓冲区高速缓存检查点),这种情况在提交时或当重做缓冲区几乎已满时发生。随后,如果您频繁提交,则会导致额外的I / O,因此我想知道如何减少 I / O。
mustaccio 2015年

4
您可能想读汤姆·凯特(Tom Kyte)关于“频繁提交”的内容:asktom.oracle.com/pls/apex / ...错,错,错。太错了……。非常非常错了
a_horse_with_no_name
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.