我有一个主表(比如说tableA的列tab_a_id,field_code和field_id)。还有另一个表,比如说tableB,它具有area_id和area_code列。 tab_a_id是TableA的主键。我想根据field_code更新tableA的field_id。 tableA的field_code和tableB的area_code匹配但不相同,这意味着field_code具有与area_code列不匹配的其他值。我想设置field_id = area_id,如果field_code = area_code,但如果不匹配,则应将其设置为默认值-1,即“未知”字段。我尝试了子查询和批量更新(例如,更新tableA SET field_id =(从tableB中选择area_code,其中area_code = field_code))。这适用于有限的数据集。但是我有300万条匹配记录,这意味着300万个子查询。另一个问题是有700万条记录,导致400万条不匹配的记录和无用的子查询。 是否有任何最佳方法可以以最少的时间和更高的效率更新此类记录。我尝试了合并命令,但与forall循环查询相比,它的性能较差
答案 0 :(得分:1)
更新700万行中的3行似乎是这里的问题。
我已经在一台小型计算机上的数据库中创建了一个测试集,获取结果的快速方法是使用所需的数据和以后的交换名称创建一个新表(CTAS)。我没有使用主键列tab_a_id来简化答案。
CREATE TABLE a (field_id NUMBER, field_code VARCHAR2(30)) NOLOGGING;
CREATE TABLE b (area_id NUMBER, area_code VARCHAR2(30)) NOLOGGING;
使用MERGE
和UPDATE
的速度非常慢(15分钟),可能是因为更改量很大:
UPDATE a SET field_id=-1 WHERE field_code NOT IN (SELECT area_code FROM b);
5,599,989 rows updated. (560 seconds)
MERGE INTO a USING b ON (a.field_code=b.area_code)
WHEN MATCHED THEN UPDATE SET a.field_id = b.area_id;
2,400,011 rows merged. (232 seconds)
但是,使用更改后的数据创建新表的速度要快20倍,并且只需38秒:
CREATE TABLE x NOLOGGING AS
SELECT a.field_id, NVL(b.area_code, -1) AS field_code
FROM a JOIN b ON a.field_code=b.area_code;
这是测试数据生成:
INSERT /*+ APPEND */ INTO a (field_id, field_code) SELECT id, to_char(id) from (select level as id from dual connect by rownum <= 1000000); COMMIT;
INSERT /*+ APPEND */ INTO a (field_id, field_code) SELECT field_id+1000000, to_char(field_id+1000000) from a; COMMIT;
INSERT /*+ APPEND */ INTO a (field_id, field_code) SELECT field_id+2000000, to_char(field_id+2000000) from a; COMMIT;
INSERT /*+ APPEND */ INTO a (field_id, field_code) SELECT field_id+4000000, to_char(field_id+4000000) from a; COMMIT;
EXEC dbms_stats.gather_table_stats(null, 'a');
INSERT /*+ APPEND */ INTO b (area_id, area_code) SELECT -field_id, field_code FROM a SAMPLE (30);
exec dbms_stats.gather_table_stats(null, 'b');