我有一个运行在DB链接上的半复杂视图;4个大表的内部连接和5个中等大小表的左连接。
问题在于:当我在SQL Developer(或SQL*Plus)中测试视图时,它似乎很好,没有任何重复。然而,当我实际使用视图将数据插入表中时,我会得到大量的重复项。
编辑:- 数据正在插入一个空表中。查询中的所有表都在数据库链接上。查询中唯一传递的是一个日期(例如INSERT INTO target SELECT * FROM view WHERE view.datecol = dQueryDate) -
我尝试在选择语句中添加一个ROW_NUMBER()函数,按PK对其进行分区。所有行都标记为1。然而,同样的语句作为插入运行时会生成与之前相同的重复项,现在方便地编号。每个键的重复行数不同。有些记录存在4次,有些只存在一次。
我发现这种行为非常令人困惑。 :) 这让我想起了与Teradata一起工作的情况,其中有SET表(仅唯一行)和MULTISET表(允许重复行),但Oracle没有这样的功能。
返回客户端的选择行应与插入到另一个位置的行完全相同。我无法想象这种情况会有合法的理由,但也许我正在遭受想象力的失败。 ;)
我想知道是否还有其他人经历过这种情况,或者这是该平台上的一个错误。
解决方案
感谢@Gary,通过使用“EXPLAIN PLAN FOR {my query};”和“SELECT * FROM TABLE(dbms_xplan.display);”,我能够找到问题的根源。实际用于INSERT的解释与SELECT非常不同。
对于SELECT,大多数计划操作都是'TABLE ACCESS BY INDEX ROWID'和'INDEX UNIQUE SCAN'。'Predicate Information'块包含查询中的所有连接和过滤器。最后它说“Note - fully remote statement”。
对于INSERT,没有引用索引。'Predicate Information'块只有三行,一个新的'Remote SQL'块显示9个小SQL语句。
数据库将我的查询拆分为9个子查询,然后尝试在本地进行连接。通过运行较小的选择,我已经找到了重复项的来源。
我认为这是Oracle编译器在远程链接方面的一个错误。当重写SQL时,它会导致逻辑上的缺陷。基本上,编译器没有正确地应用WHERE子句。我刚刚进行了测试,并给出了一个包含5个键的IN列表以返回。SELECT将返回5行。INSERT将77,000多行放入目标中,并完全忽略了IN列表。
{仍在寻找一种强制正确行为的方法,我可能不得不要求在远程数据库上创建视图,尽管从开发角度来看这并不理想。我在成功后会编辑此内容...}