Frage

Ich bin immer ein seltsames Verhalten aus einer Oracle-Instanz arbeite ich an. Dies ist 11gR1 auf Itanium, ohne RAC, nichts Besonderes. Ich bewege Daten von einer Oracle-Instanz zu einem anderen letztlich in einem Data Warehouse-Szenario.

Ich habe einen halb Komplex Blick über einen DB-Link ausgeführt wird; 4 Innen schließt sich über groß ish Tabellen und 5 links schließt sich über mittelgroße Tabellen.

Hier ist das Problem: Wenn ich die Ansicht in SQL Developer testen (oder SQL * Plus) scheint es in Ordnung, keine Duplizierung auch immer. Allerdings, wenn ich tatsächlich die Ansicht verwenden, um Daten in eine Tabelle einfügen ich eine große Anzahl von Duplikaten erhalten.

EDIT: - Die Daten in eine leere Tabelle wird. Alle Tabellen in der Abfrage sind auf dem Datenbank-Link. Das einzige, was in die Abfrage übergeben ist ein Datum (zum Beispiel in Ziel SELECT * FROM INSERT Ansicht WHERE view.datecol = dQueryDate) -

Ich habe versucht, eine ROW_NUMBER () Funktion auf die select-Anweisung hinzugefügt, durch die PK für die Ansicht geteilt. Alle Zeilen kommen nummeriert als 1. Wieder zurück aber die gleiche Aussage als Insert ausführen erzeugt die gleichen Betrogenen wie zuvor und jetzt bequem nummeriert. Die Zahl der betrogenen Reihen ist nicht das gleiche pro Taste. Einige Aufzeichnungen existieren 4 mal einige nur einmal vorhanden sein.

Das finde ich auf das Verhalten extrem verwirrend zu sein. :) Es erinnert mich mit Teradata arbeiten, wo Sie Tabellen haben (eindeutige Zeilen nur) und MULTISET Tabellen (doppelte Zeilen erlaubt), aber Oracle hat keine solche Funktionalität.

Ein wählen, die Zeilen an den Client zurückgibt sollten identisch zu einem Verhalten, das diese Zeilen an eine andere Stelle einfügt. Ich kann nicht einen berechtigten Grund dafür vorstellen passieren, aber vielleicht von einem Versagen der Phantasie ich leide. ;)

Ich frage mich, ob jemand anderes erlebt hat dies oder wenn es einen Fehler auf dieser Plattform.

SOLUTION

Dank @Gary, konnte ich auf den Grund erhalten, indem Sie „EXPLAIN PLAN FÜR {my query};“ und "SELECT * FROM TABLE (dbms_xplan.display);". Die das erklärt tatsächlich verwendet wird für die INSERT ist sehr verschieden von der SELECT.

Für die SELECT meisten der Plan Operationen sind 'TABLE ACCESS BY INDEX ROWID' und 'INDEX UNIQUE SCAN'. Der Block ‚Predicate Information‘ enthält alle die Verknüpfungen und Filter aus der Abfrage. Am Ende heißt es "Hinweis - voll Remote-Anweisung" .

Für die INSERT gibt es keinen Hinweis auf die Indizes. Der Block 'Predicate Information' ist nur drei Linien und eine neue 'Remote SQL' Block zeigt 9 kleine SQL-Anweisungen.

Die Datenbank hat meine Abfrage in 9 Unterabfragen aufgeteilt und dann versucht, sie vor Ort zu verbinden. Durch den Betrieb der kleineren wählt Ich habe die Quelle der Duplikate entfernt.

Ich glaube, dass dieser Fehler in den Oracle-Compiler um Remote-Verbindungen ist. Es schafft logische Fehler, wenn die SQL neu zu schreiben. Grundsätzlich ist der Compiler nicht richtig ist die Anwendung der WHERE-Klausel. Ich testete es und gab es eine in der Liste der 5 Tasten zurück zu bringen. SELECT bringt wieder 5 Reihen. INSERT setzt 77,000+ Zeilen in das Ziel und völlig ignoriert die IN-Liste.

{immer noch nach einem Weg suchen, um das richtige Verhalten zu zwingen, kann ich für die Ansicht fragen, in der entfernten Datenbank erstellt werden, obwohl das nicht ideal aus entwicklungs Sicht ist. Ich werde diese bearbeiten, wenn ich habe es funktioniert ...}

War es hilfreich?

Lösung

Es scheint Oracle Bug zu sein, haben wir diesen folgenden workarround gefunden: Wenn Sie möchten, dass Ihre „insert into select ...“ Arbeit wie Ihre „select ...“, Sie wählen in einem Unter wählen packen kann.

Zum Beispiel:

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

-> kein Duplikat

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

-> doppelte Fehler

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

-> kein Duplikat

Viele Grüße

Andere Tipps

Eine Sache, die den Sinn kommt, ist, dass im Allgemeinen ein Optimierer Plan für eine SELECT einen FIRST_ROWS Plan bevorzugen Reihen an den Anrufer zurück zu geben zu früh, aber eine INSERT ... SELECT wird einen ALL_ROWS Plan bevorzugen, da es haben wird, um den vollständigen Datensatz zu liefern. Ich würde die Abfragepläne überprüfen DBMS_XPLAN.DISPLAY_CURSOR mit (die sql_id von V $ SQL verwenden).

  

Ich habe einen halb komplexe Ansicht Lauf   DB über einen Link; 4 schließt sich über Innen   groß-ish Tabellen und 5 links schließt sich über   mittelgroße Tabellen.   ...   Alle Tabellen in der Abfrage sind auf   der Datenbank-Link

Wieder ein potenzielles Problem vor Ort. Wenn alle Tabellen in der SELECT am anderen Ende der Verbindung DB wären, würde die gesamte Abfrage an die entfernten Datenbank gesendet werden und die Ergebnismenge zurückgegeben. Sobald Sie die INSERT in werfen, ist es wahrscheinlicher, dass die lokale Datenbank verantwortlich für die Abfrage nehmen und Tabellen über alle Daten aus dem Kind ziehen. Aber das kann davon abhängen, ob die Ansicht in der lokalen Datenbank oder die entfernten Datenbank definiert ist. Im letzteren Fall, so weit wie die lokalen Optimierer es betrifft, ist nur ein entferntes Objekt und es wird Daten aus, dass, und die entfernte Datenbank tut der Verbindung.

Was passiert, wenn Sie nur an die Remote-DB gehen und auf einem Tisch gibt die INSERT tun?

Das ist ein Fehler in Oracles Umgang mit über DB Links verbindet. Ich habe eine einfachere Situation, die nicht eine INSERT gegen SELECT beinhaltet. Wenn ich meine remote Abfrage ausführen, bekomme ich doppelte Zeilen, aber wenn ich es lokal ausführen, das tue ich nicht. Der einzige Unterschied zwischen den Abfragen ist die „@ ...“, um die Tabellen in der Remote-Abfrage angehängt. Ich bin eine 9i-Datenbank aus einer 10.2-Datenbank mit SQL Developer Abfragen 3.0.

Das noch dümmer als die Fehler in Oracle, die Sie von der Teilnahme an Tabellen mit mehr als 1000 insgesamt Spalten verhindert, die sehr einfach zu tun, wenn das ERP-System abfragen. Und nein, ist die Fehlermeldung nichts über Tabellen zu viele Spalten.

Es ist fast so dumm, wie diese anderen Oracle-Datenbank-Fehler, die Abfrage von Tabellen mit LOB Locators mit ANSI-Syntax verbietet. Nur Oracle-Syntax funktioniert!

Mehr Optionen kommen zu mir.

  1. Die Betrogene Sie sehen, waren bereits in der Zieltabelle ??

  2. Wenn in Ihrem Select, Sie verweisen auf die Tabelle, die Sie in einfügen, (?), Dann der Einsatz mit dem Auswahlinteragiert in Ihrem kombinierte

    Einfügen ... auswählen ... Von ...

In einer solchen Art und Weise (kartesischer Produkte?) Als die Duplikate erstellen

kann ich nicht helfen, denke aber, dass vielleicht sind Sie einen Nebeneffekt von etwas anderes auf den Tisch im Zusammenhang erleben. Gibt es irgendwelche Auslöser, die Daten werden manipuliert kann?

Wie haben Sie feststellen, dass es keine Duplikate in der ursprünglichen Tabelle?

Wie andere bereits erwähnt haben dies scheint die einfachste Erklärung für dieses seltsame Verhalten zu sein.

Überprüfen Sie Ihre JOINs sorgfältig. Möglicherweise haben Sie in den einzelnen Tabellen keine Duplikate, sondern underspecified verbinden inadvertant CROSS JOINs verursachen können, so dass Ihre Ergebnismengen Duplikate aufgrund Vielzahl haben und, wenn eingesetzt, dies eine Eindeutigkeitsbedingung in Ihrer Zieltabelle verletzt.

Was ich in diesem Fall tun, ist die Abfrage in einer Ansicht oder CTE zu nisten und versuchen, die Duplikate direkt aus dem SELECT zu erkennen:

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

Ich würde vorschlagen, einen Plan für die Abfrage immer da drin Sie laufen und suchen nach einem CARTESIAN JOIN. Dies könnte eine fehlende Bedingung angeben, die duplizierten Zeilen verursacht.

AS @Pop hat bereits dieses Verhalten vorgeschlagen passieren könnte, wenn Sie eine andere Anmeldung in SQLPlus zum Login verwenden, wenn Ihr Einsatz läuft. (Das heißt, wenn die andere Login eine Tabelle / view / Synonym mit dem gleichen Namen hat)

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top