问题
我正在尝试将性能低下的MERGE
语句重构为UPDATE
Oracle 12.1.0.2.0 中的语句。该MERGE
声明如下所示:
MERGE INTO t
USING (
SELECT t.rowid rid, u.account_no_new
FROM t, u, v
WHERE t.account_no = u.account_no_old
AND t.contract_id = v.contract_id
AND v.tenant_id = u.tenant_id
) s
ON (t.rowid = s.rid)
WHEN MATCHED THEN UPDATE SET t.account_no = s.account_no_new
它主要是低性能的,因为对大型(100M 行)表有两次昂贵的访问t
架构
这些是所涉及的简化表:
t
account_no
正在迁移其列的目标表。u
包含account_no_old
→account_no_new
映射的迁移指令表v
contract_id
一个辅助表模拟和之间的一对一关系tenant_id
架构是:
CREATE TABLE v (
contract_id NUMBER(18) NOT NULL PRIMARY KEY,
tenant_id NUMBER(18) NOT NULL
);
CREATE TABLE t (
t_id NUMBER(18) NOT NULL PRIMARY KEY,
-- tenant_id column is missing here
account_no NUMBER(18) NOT NULL,
contract_id NUMBER(18) NOT NULL REFERENCES v
);
CREATE TABLE u (
u_id NUMBER(18) NOT NULL PRIMARY KEY,
tenant_id NUMBER(18) NOT NULL,
account_no_old NUMBER(18) NOT NULL,
account_no_new NUMBER(18) NOT NULL,
UNIQUE (tenant_id, account_no_old)
);
我无法修改架构。我知道添加t.tenant_id
将通过阻止 JOIN 来解决问题v
替代 MERGE 不起作用:
ORA-38104: ON 子句中引用的列无法更新
请注意,无法避免自连接,因为这种替代的等效查询会导致 ORA-38104:
MERGE INTO t
USING (
SELECT u.account_no_old, u.account_no_new, v.contract_id
FROM u, v
WHERE v.tenant_id = u.tenant_id
) s
ON (t.account_no = s.account_no_old AND t.contract_id = s.contract_id)
WHEN MATCHED THEN UPDATE SET t.account_no = s.account_no_new
更新视图不起作用:
ORA-01779: 无法修改映射到非键保留表的列
直观地说,我会在这里应用传递闭包,这应该保证对于 in 中的每个更新行,in和 int
最多只能有 1 行。但显然,Oracle 不承认这一点,因此以下语句不起作用:u
v
UPDATE
UPDATE (
SELECT t.account_no, u.account_no_new
FROM t, u, v
WHERE t.account_no = u.account_no_old
AND t.contract_id = v.contract_id
AND v.tenant_id = u.tenant_id
)
SET account_no = account_no_new
以上提出ORA-01779
。添加未记录的提示/*+BYPASS_UJVC*/
似乎不再适用于 12c。
如何告诉 Oracle 该视图是密钥保留?
在我看来,视图仍然是保留键的,即对于 中的每一行t
,在 中恰好有一行v
,因此在 中最多只有一行u
。因此视图应该是可更新的。有没有办法重写这个查询,让 Oracle 相信我的判断?
或者是否有任何其他我忽略的语法阻止MERGE
语句的双重访问t
?