我目前正在使用Oracle 11g,假设我有一个包含以下列的表(或多或少)
表1
此表格大约有<10亿行。我想用特定的where子句更新 status 列,比如说
where transaction_date = somedatehere
我可以使用哪些其他替代方法而不仅仅是普通的UPDATE语句?
目前,我正在尝试使用 CTAS或插入选择来获取我想要更新的行,并在使用 AS COLUMN_NAME 时放入另一个表格所以这些值已在新/临时表上更新,如下所示:
INSERT INTO TABLE1_TEMPORARY (
ID,
STATUS,
TRANSACTION_DATE,
TONS_OF_OTHER_COLUMNS)
SELECT
ID
3 AS STATUS,
TRANSACTION_DATE,
TONS_OF_OTHER_COLUMNS
FROM TABLE1
WHERE
TRANSACTION_DATE = SOMEDATE
到目前为止,一切似乎都比普通的更新语句更快。现在的问题是我想从原始表中获取剩余的数据,我不需要更新,但我需要包含在我更新的表/列表中。
我最初尝试做的是使用相同的where子句在同一个原始表上使用 DELETE ,这样理论上,应该留在该表上的所有内容都应该是我的所有数据不需要更新,现在留下我的两个表:
TABLE1 --which now contains the rows that i did not need to update
TABLE1_TEMPORARY --which contains the data I updated
但是删除语句本身也太慢或者比原始UPDATE语句慢所以没有删除语句会让我到这一步。
TABLE1 --which contains BOTH the data that I want to update and do not want to update
TABLE1_TEMPORARY --which contains the data I updated
我可以使用哪些其他替代方法来获取与我的WHERE子句相反的数据(请注意,此示例中的where子句已经简化,所以我不是在寻找 NOT EXISTS / NOT IN / NOT EQUALS 加上那些条款与正条款相比也较慢)
我已经排除了分区删除,因为我需要更新和不更新的数据可以存在于不同的分区中,以及TRUNCATE,因为我没有更新所有数据,只是其中的一部分。
我在TABLE1和TABLE1_TEMPORARY中使用了某种JOIN语句来过滤掉不需要更新的数据吗?
我也希望尽可能减少REDO / UNDO / LOGGING来实现这一目标。
提前致谢。
答案 0 :(得分:1)
我假设这不是一次性操作,但您正在尝试设计可重复的过程。
以某种方式对表进行分区/子分区,使触摸的行不会完全分布在所有分区上,而是局限于几个分区。
确保您的交易暂时不使用这些分区。
每个分区/子分区通常都会更新,执行所有行的CTAS(我的意思是即使是保持相同的行也会转到TABLE1_TEMPORARY)。然后EXCHANGE PARTITION并重建索引分区。
最后重建全局索引。
如果您没有Oracle Enterprise Edition,则需要CTAS全部十亿行(后跟ALTER TABLE RENAME而不是ALTER TABLE EXCHANGE PARTITION)或使用视图准备某种“穷人的分区” (SELECT UNION ALL SELECT UNION ALL SELECT等)和一堆表。
这个混乱实际上有可能比UPDATE更快。
我不是说这是优雅或最优的,我说这是加速Oracle中大型UPDATE操作的规范方法。
答案 1 :(得分:1)
如何在同一张桌子中保留UPDATE
,但将其分成多个小块?
UPDATE .. WHERE transaction_date = somedatehere AND id BETWEEN 0000000 and 0999999
COMMIT
UPDATE .. WHERE transaction_date = somedatehere AND id BETWEEN 1000000 and 1999999
COMMIT
UPDATE .. WHERE transaction_date = somedatehere AND id BETWEEN 2000000 and 2999999
COMMIT
如果总工作负载可能是可管理的,那么这可能有所帮助,但是在一个块中完成所有工作是问题。这种方法将其分解为适度大小的部分。
例如,这样做可以使其他应用程序继续运行&amp;让其他工作负载看看;并且会避免在日志文件中需要一个单一的重要事务。