sql - 使用大表时提高 MERGE 性能

标签 sql oracle oracle11g

上下文

我们有一个模型,其中每个元素都有一个元素种类和0到N个特征。每个特征仅属于一个元素并具有一个特征名称

建模如下表:

ELEMENTS
  elem_id int not null -- PK
  elem_elki_id int not null -- FK to ELEMENT_KINDS
  -- more columns with elements data

ELEMENT_KINDS
  elki_id int not null -- PK
  -- more columns with elements kinds data

FEATURES
  feat_id int not null -- PK
  feat_elem_id int not null -- FK to ELEMENTS  
  feat_fena_id int not null -- FK to FEATURE_NAMES
  -- more columns with features data

FEATURE_NAMES
  fena_id int not null -- PK
  -- more columns with feature_names data


要求

有一项新要求,即用要素种类 表替换要素名称 表。 每个(元素种类,特征名称) 对都有一个(且仅有一个)特征种类

模型中的更改是添加新列并创建新表:

ALTER TABLE features ADD feat_feki_id int null;

CREATE TABLE FEATURE_KINDS
(
  feki_id int not null, -- PK
  feki_elki_id int not null, -- FK to ELEMENT_KINDS
  feki_fena_id int null, -- FK* to FEATURE_NAMES
  -- more columns with feature kinds data
)

*feki_fena_id 实际上是一个临时列,显示哪个功能名称 用于创建每种功能类型。填充 feat_feki_id 后,feki_fena_id 应与 feat_fena_id功能名称 表一起丢弃。


问题

成功填充features kind表后,我们尝试使用以下查询填充feat_feki_id列:

MERGE INTO features F
USING
(
    SELECT *
    FROM elements
    INNER JOIN feature_kinds
    ON elem_elki_id = feki_elki_id
) EFK
ON
(
    F.feat_elem_id = EFK.elem_id AND
    F.feat_fena_id = EFK.feki_fena_id
)
WHEN MATCHED THEN
UPDATE SET F.feat_feki_id = EFK.feki_id;

这适用于带有测试数据的小案例场景,但在生产中我们有~2000万元素~2000feature_kinds 并且大约需要一个小时才会抛出ORA-30036:无法在撤消表空间'UNDOTBS1'中将段扩展8错误。


问题

有什么方法可以提高 MERGE 的性能,使其正常工作吗? (也许我缺少一些索引?)

还有其他替代方法来填写 feat_feki_id 列吗? (我们已经尝试使用 UPDATE 而不是 MERGE 获得类似的结果)

最佳答案

目前尚不清楚是否出现了问题,或者您的撤消段是否太小。您可以在不得到 ORA-30036 的情况下执行以下语句吗?

UPDATE features f SET f.feat_feki_id = 12345;

如果这不起作用,您只需增加撤消段的大小即可。 Kludges 可用于分块进行更新,但您实际上不必这样做。

假设这不是一个简单的 UNDO 大小问题,您可以做的一件事是确保您的 MERGE (或 UPDATE)按照行出现的顺序更新行你的 table 。否则,您可能会一遍又一遍地重新访问相同的 block ,这确实会损害性能并增加 UNDO 使用率。几年前,我在一次类似的操作中遇到了这个问题,当我最终弄清楚时,我感到很震惊。

为了避免我遇到的问题,你需要这样的东西:

MERGE INTO features F
USING
(
    SELECT f.feat_id, fk.feki_id
    FROM features f
    INNER JOIN elements e ON e.elem_id = f.feat_elem_id
    INNER JOIN feature_kinds fk ON fk.feki_elki_id = e.elem_elki_id and fk.feki_fena_id = f.feat_fena_id
    -- Order by the ROWID of the table you are updating to ensure you are not revisiting the same block over and over
    ORDER BY f.rowid
) EFK
ON
(
    F.feat_id = efk.feat_id )
)
WHEN MATCHED THEN
UPDATE SET F.feat_feki_id = EFK.feki_id;

我可能弄错了您的数据模型,但关键点是在 MERGE 查询中包含 FEATURES 表和 ORDER BY features.rowid 确保更新按行顺序发生。

关于sql - 使用大表时提高 MERGE 性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41350840/

相关文章:

用于限制组内行的 SQL 查询

mysql - 我需要选择条件这个

java - 无法使用以下凭据连接到数据库 :jdbc:oracle:thin@:smthing

sql - Oracle 临时表空间更改语句

PHP/SQL/Mysql/phpmyadmin - 外键

sql - TO_NUMBER 号码无效错误

java - 如何将大量数据从数据库存储到 XML(内存问题)?

java - 如何在本地网络上连接Java与oracle 8i数据库

java - 解释 JDBC 连接

sql - Oracle 中的字符串顺序分组