English 中文(简体)
Oracle bug? SELECT returns no dupes, INSERT from SELECT has duplicate rows
原标题:

I m getting some strange behaviour from an Oracle instance I m working on. This is 11gR1 on Itanium, no RAC, nothing fancy. Ultimately I m moving data from one Oracle instance to another in a data warehouse scenario.

I have a semi-complex view running over a DB link; 4 inner joins over large-ish tables and 5 left joins over mid-size tables.

Here s the problem: when I test the view in SQL Developer (or SQL*Plus) it seems fine, no duplication whatsoever. However, when I actually use the view to insert data into a table I get a large number of dupes.

EDIT: - The data is going into an empty table. All of the tables in the query are on the database link. The only thing passed into the query is a date (e.g. INSERT INTO target SELECT * FROM view WHERE view.datecol = dQueryDate) -

I ve tried adding a ROW_NUMBER() function to the select statement, partitioned by the PK for the view. All rows come back numbered as 1. Again though, the same statement run as an insert generates the same dupes as before and now conveniently numbered. The number of duped rows is not the same per key. Some records exist 4 times some only exist once.

I find this to behaviour to be extremely perplexing. :) It reminds me of working with Teradata where you have SET tables (unique rows only) and MULTISET tables (duplicate rows allowed) but Oracle has no such functionality.

A select that returns rows to the client should behave identically to one that inserts those rows to another location. I can t imagine a legitimate reason for this to happen, but maybe I m suffering from a failure of imagination. ;)

I wonder if anyone else has experienced this or if it s a bug on this platform.

SOLUTION

Thanks to @Gary, I was able to get to the bottom of this by using "EXPLAIN PLAN FOR {my query};" and "SELECT * FROM TABLE(dbms_xplan.display);". The explain that actually gets used for the INSERT is very different from the SELECT.

For the SELECT most of the plan operations are TABLE ACCESS BY INDEX ROWID and INDEX UNIQUE SCAN . The Predicate Information block contains all of the joins and filters from the query. At the end it says "Note - fully remote statement".

For the INSERT there is no reference to the indexes. The Predicate Information block is just three lines and a new Remote SQL block shows 9 small SQL statements.

The database has split my query into 9 subqueries and then attempts to join them locally. By running the smaller selects I ve located the source of the duplicates.

I believe this is bug in the Oracle compiler around remote links. It creates logical flaws when re-writing the SQL. Basically the compiler is not properly applying the WHERE clause. I was just testing it and gave it an IN list of 5 keys to bring back. SELECT brings back 5 rows. INSERT puts 77,000+ rows into the target and totally ignores the IN list.

{Still looking for a way to force the correct behaviour, I may have to ask for the view to be created on the remote database although that is not ideal from a development viewpoint. I ll edit this when I ve got it working…}

最佳回答

It seems to be Oracle Bug, we have found this following workarround: If you want that your "insert into select ..." work like your "select ...", you can pack your select in a sub select.

For example :

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

--> no duplicate

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

--> duplicate error

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

--> no duplicate

Regards

问题回答

One thing that comes to mind is that generally an optimizer plan for a SELECT will prefer a FIRST_ROWS plan to give rows back to the caller early, but an INSERT...SELECT will prefer an ALL_ROWS plan as it is going to have to deliver the full dataset. I d check the query plans using DBMS_XPLAN.DISPLAY_CURSOR (using the sql_id from V$SQL).

I have a semi-complex view running over a DB link; 4 inner joins over large-ish tables and 5 left joins over mid-size tables. ... All of the tables in the query are on the database link

Again, a potential trouble-spot. If all the tables in the SELECT were on the other end of the DB link, the whole query would be sent to the remote database and the resultset returned. Once you throw the INSERT in, it is more likely that the local database will take charge of the query and pull all the data from the child tables over. But that may depend on whether the view is defined in the local database or the remote database. In the latter case, as far as the local optimizer is concerned there is just one remote object and it gets data from that, and the remote database will do the join.

What happens if you just go to the remote DB and do the INSERT on a table there ?

This is a bug in Oracle s handling of joins over DB links. I have a simpler situation which does not involve an INSERT versus SELECT. If I run my query remotely, I get duplicate rows, but if I run it locally, I do not. The only difference between the queries is the "@..." appended to the tables in the remote query. I am querying a 9i database from a 10.2 database using Oracle SQL Developer 3.0.

This even more stupid than that bug in Oracle which prevents you from joining tables with more than 1000 total columns, which is VERY easy to do when querying the ERP system. And no, the error message is nothing about tables having too many columns.

It s almost as stupid as that other Oracle database bug that prohibits querying tables containing LOB locators using ANSI syntax. Only Oracle syntax works!

Several options occur to me.

  1. The dupes you see were already in the destination table ??

  2. If in your Select, you reference the table you are Inserting into, ( ? ), then The Insert is interacting with the select in your combined

    Insert ... Select ... From ...

In such a way (cartesian products ?) as to create the duplicates

I can t help but think that maybe you are experiencing a side-effect from something else related to the table. Are there any triggers which may be manipulating data?

How did you determine that there are no dupes in the original table?

As others have noted this seems to be the simpledst explanation for this strange behaviour.

Check your JOINs carefully. Potentially you have no duplicates in the individual tables, but underspecified joins can cause inadvertant CROSS JOINs so that your result set has duplicates due to multiplicity and, when inserted, this violates a uniqueness constraint in your destination table.

What I do in this case is to nest the query in a view or CTE and try to detect the duplicates straight from the SELECT:

WITH resultset AS (
    -- blah, blah
)
SELECT a, b, c, COUNT(*)
FROM resultset
GROUP BY a, b, c
HAVING COUNT(*) > 1

I would suggest getting a plan on the query you are running and looking for a CARTESIAN JOIN in there. This could indicate a missing condition that is causing duplicated rows.

AS @Pop has already suggested this behaviour could happen if you are using a different login in SQLPlus to the login when your insert is running. (That is if the other login has a table/view/synonym with the same name)





相关问题
Export tables from SQL Server to be imported to Oracle 10g

I m trying to export some tables from SQL Server 2005 and then create those tables and populate them in Oracle. I have about 10 tables, varying from 4 columns up to 25. I m not using any constraints/...

Connecting to Oracle 10g with ODBC from Excel VBA

The following code works. the connection opens fine but recordset.recordCount always returns -1 when there is data in the table. ANd If I try to call any methods/properties on recordset it crashes ...

How to make a one to one left outer join?

I was wondering, is there a way to make a kind of one to one left outer join: I need a join that matches say table A with table B, for each record on table A it must search for its pair on table B, ...

Insert if not exists Oracle

I need to be able to run an Oracle query which goes to insert a number of rows, but it also checks to see if a primary key exists and if it does, then it skips that insert. Something like: INSERT ALL ...

How can I store NULLs in NOT NULL field?

I just came across NULL values in NOT-NULL fields in our test database. How could they get there? I know that NOT-NULL constraints can be altered with NOVALIDATE clause, but that would change table s ...

Type reference scope

I m studying databases and am currently working on a object-relational DB project and I ve encountered a small problem with the number of possible constraints in an object table. I m using "Database ...

OracleParameter and DBNull.Value

we have a table in an Oracle Database which contains a column with the type Char(3 Byte). Now we use a parameterized sql to select some rows with a DBNull.Value and it doesn t work: OracleCommand ...

热门标签