UPDATE语句Oracle 11g的替代方法

时间:2013-11-16 11:22:54

标签: sql performance oracle11g

我目前正在使用Oracle 11g,假设我有一个包含以下列的表(或多或少)

表1

  • ID varchar(64)
  • 状态int(1)
  • Transaction_date date
  • 吨其他专栏

此表格大约有<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来实现这一目标。

提前致谢。

2 个答案:

答案 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;让其他工作负载看看;并且会避免在日志文件中需要一个单一的重要事务。