7

我正在处理的 Oracle 实例出现一些奇怪的行为。这是 Itanium 上的 11gR1,没有 RAC,没什么特别的。最终,我在数据仓库场景中将数据从一个 Oracle 实例移动到另一个实例。

我有一个通过数据库链接运行的半复杂视图;大型表上有 4 个内连接,中型表上有 5 个左连接。

这就是问题所在:当我在 SQL Developer(或 SQL*Plus)中测试视图时,它看起来很好,没有任何重复。但是,当我实际使用视图将数据插入表中时,我得到了大量的欺骗。

编辑: - 数据将进入一个空表。查询中的所有表都在数据库链接上。唯一传入查询的是日期(例如 INSERT INTO target SELECT * FROM view WHERE view.datecol = dQueryDate) -

我尝试将 ROW_NUMBER() 函数添加到 select 语句中,由视图的 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'。“谓词信息”块包含查询中的所有连接和过滤器。最后它说“注意 - 完全远程声明”

对于 INSERT,没有对索引的引用。“谓词信息”块只有三行,一个新的“远程 SQL”块显示9个小 SQL 语句。

数据库已将我的查询拆分为 9 个子查询,然后尝试在本地加入它们。通过运行较小的选择,我找到了重复项的来源。

我相信这是 Oracle 编译器中围绕远程链接的错误。重写 SQL 时会产生逻辑缺陷。基本上编译器没有正确应用 WHERE 子句。我只是在测试它并给它一个包含 5 个键的 IN 列表以恢复。SELECT 带回 5 行。INSERT 将 77,000 多行放入目标中,并完全忽略 IN 列表。

{仍在寻找一种强制正确行为的方法,我可能不得不要求在远程数据库上创建视图,尽管从开发的角度来看这并不理想。当我让它工作时,我会编辑它…}

4

9 回答 9

6

这似乎是 Oracle 错误,我们发现了以下解决方法:如果您希望您的“ insert into select ...”像您的“”一样工作select ...,您可以将您的选择打包在一个子选择中。

例如 :

select x,y,z from table1, table2, where ...

--> 没有重复

insert into example_table
select x,y,z from table1, table2, where ...

--> 重复错误

insert into example_table
select * from (
       select x,y,z from table1, table2, where ...
)

--> 没有重复

问候

于 2013-04-11T07:42:36.520 回答
3

想到的一件事是,通常 SELECT 的优化器计划会更喜欢 FIRST_ROWS 计划,以便尽早将行返回给调用者,但是 INSERT...SELECT 会更喜欢 ALL_ROWS 计划,因为它必须交付完整的数据集。我会使用 DBMS_XPLAN.DISPLAY_CURSOR(使用 V$SQL 中的 sql_id)检查查询计划。

我有一个通过数据库链接运行的半复杂视图;大型表上有 4 个内连接,中型表上有 5 个左连接。...查询中的所有表都在数据库链接上

再次,一个潜在的麻烦点。如果 SELECT 中的所有表都在 DB 链接的另一端,则整个查询将被发送到远程数据库并返回结果集。一旦您将 INSERT 放入其中,本地数据库更有可能负责查询并从子表中提取所有数据。但这可能取决于视图是在本地数据库中还是在远程数据库中定义的。在后一种情况下,就本地优化器而言,只有一个远程对象,它从中获取数据,远程数据库将执行连接。

如果您只是去远程数据库并在那里的表上执行 INSERT 会发生什么?

于 2009-12-08T21:34:50.430 回答
1

这是 Oracle 处理 DB 链接上的连接时的一个错误。我有一个更简单的情况,它不涉及 INSERT 与 SELECT。如果我远程运行我的查询,我会得到重复的行,但如果我在本地运行它,我不会。查询之间的唯一区别是附加到远程查询中的表的“@...”。我正在使用 Oracle SQL Developer 3.0 从 10.2 数据库中查询 9i 数据库。

这比 Oracle 中的错误更愚蠢,它阻止您加入总列数超过 1000 的表,这在查询 ERP 系统时很容易做到。不,错误消息与具有太多列的表无关。

它几乎与其他 Oracle 数据库错误一样愚蠢,该错误禁止使用 ANSI 语法查询包含 LOB 定位器的表。只有 Oracle 语法有效!

于 2011-11-15T23:12:14.980 回答
0

我建议制定一个关于您正在运行的查询的计划,并在那里寻找一个笛卡尔连接。这可能表示导致重复行的缺失条件。

于 2009-12-09T00:34:57.593 回答
0

我有几个选择。

  1. 你看到的骗子已经在目标表中了??

  2. 如果在您的 Select 中,您引用了要插入的表(?),那么 Insert 正在与您组合中的选择进行交互

    插入 ... 选择 ... 从 ...

以这种方式(笛卡尔积?)创建重复项

于 2009-12-08T17:18:52.983 回答
0

JOIN仔细检查你的 s。可能您在各个表中没有重复项,但未指定的连接可能会导致意外CROSS JOINs,因此您的结果集由于多重性而具有重复项,并且在插入时,这违反了目标表中的唯一性约束。

在这种情况下,我所做的是将查询嵌套在视图或 CTE 中,并尝试直接从以下位置检测重复项SELECT

WITH resultset AS (
    -- blah, blah
)
SELECT a, b, c, COUNT(*)
FROM resultset
GROUP BY a, b, c
HAVING COUNT(*) > 1
于 2009-12-08T21:41:15.750 回答
0

AS @Pop 已经建议如果您在 SQLPlus 中使用与插入运行时的登录不同的登录名,则可能会发生这种行为。(即如果另一个登录有同名的表/视图/同义词)

于 2009-12-09T09:02:59.933 回答
0

您如何确定原始表中没有欺骗?

正如其他人所指出的,这似乎是对这种奇怪行为的最简单的解释。

于 2009-12-08T19:26:06.347 回答
0

我不禁想到,也许你正在经历与桌子相关的其他事情的副作用。是否有任何可能操纵数据的触发器?

于 2009-12-08T17:33:41.080 回答