Question

Je reçois un comportement étrange d'une instance Oracle je travaille. Ceci est 11gR1 sur Itanium, pas RAC, rien d'extraordinaire. En fin de compte je déplacer des données d'une instance Oracle à l'autre dans un scénario d'entrepôt de données.

J'ai une vue semi-complexe en cours d'exécution sur une liaison DB; 4 jointures internes sur les tables de grande rigueur et 5 gauche jointures sur des tables de taille moyenne.

Voici le problème: quand je teste la vue dans SQL Developer (ou SQL * Plus), il semble bien, pas de double emploi que ce soit. Cependant, quand je l'utilise en fait le point de vue d'insérer des données dans une table, je reçois un grand nombre de dupes.

EDIT: - Les données va dans une table vide. Toutes les tables dans la requête sont sur le lien de base de données. La seule chose passée dans la requête est une date (par exemple INSERT INTO cible SELECT * FROM vue OÙ view.datecol = dQueryDate) -

Je l'ai essayé d'ajouter une fonction ROW_NUMBER () à l'instruction select, divisée par le PK pour la vue. Toutes les lignes numérotées en reviennent comme 1. Encore une fois cependant, la même déclaration se présenter comme insert génère les mêmes dupes que précédemment et maintenant commodément numérotées. Le nombre de lignes dupés est pas la même par clé. Certains documents existent 4 fois certains existent une seule fois.

Je trouve que ce comportement est extrêmement déconcertant. :) Cela me rappelle de travailler avec Teradata où vous avez des tables SET (lignes uniques uniquement) et les tables MULTISET (lignes en double autorisées) mais Oracle n'a pas cette fonctionnalité.

Une sélection qui renvoie des lignes au client doit se comporter de façon identique à celui qui insère ces lignes à un autre endroit. Je ne peux pas imaginer une raison légitime pour que cela se produise, mais peut-être que je souffre d'un manque d'imagination. ;)

Je me demande si quelqu'un d'autre a connu cela ou si elle est un bug sur cette plate-forme.

SOLUTION

Merci à @Gary, j'ai pu aller au fond de ce en utilisant « EXPLIQUER PLAN {ma requête}; » et "SELECT * FROM TABLE (dbms_xplan.display);". L'expliquer que obtient réellement utilisé pour l'INSERT est très différent du SELECT.

Pour le SELECT la plupart des opérations du plan sont 'ACCÈS TABLE PAR INDEX ROWID' et 'INDEX UNIQUE SCAN. Le bloc « prédicats information » contient tous les joints et les filtres de la requête. A la fin, il dit "Note - déclaration complète à distance" .

Pour INSERT il n'y a pas de référence aux indices. Le bloc « prédicats information » est à seulement trois lignes et une nouvelle montre de bloc « SQL à distance » 9 petites instructions SQL.

La base de données a divisé ma requête en 9 sous-requêtes puis tente de les rejoindre sur place. En exécutant les plus petits que j'ai choisit située la source des doublons.

Je crois que c'est bogue dans le compilateur Oracle autour des liens à distance. Il crée des failles logiques lors de la réécriture du SQL. Fondamentalement, le compilateur n'applique pas correctement la clause WHERE. Je testais juste et lui a donné une liste IN 5 clés pour ramener. SELECT ramène 5 lignes. INSERT met 77,000+ lignes dans la cible et ignore totalement la liste IN.

{Toujours à la recherche d'un moyen de forcer le comportement correct, je dois demander la vue à créer sur la base de données distante bien que ce soit pas idéale d'un point de vue du développement. Je vais modifier quand je l'ai travail ...}

Était-ce utile?

La solution

Il semble Bug Oracle, nous avons trouvé cette workarround suivante: Si vous voulez que votre travail « de insert into select ... » comme votre « select ... », vous pouvez emballer votre sélection dans un sous select.

Par exemple:

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

-> pas de double

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

-> erreur de double

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

-> pas de double

Cordialement

Autres conseils

Une chose qui vient à l'esprit est que généralement un plan d'optimisation pour un SELECT préférera un plan FIRST_ROWS pour donner des lignes à l'appelant au début, mais une INSERT ... SELECT préférera un plan ALL_ROWS car il va avoir pour fournir l'ensemble des données. Je vérifie les plans de requête à l'aide DBMS_XPLAN.DISPLAY_CURSOR (en utilisant la sql_id de SQL V $).

  

J'ai une vue semi-complexe course   sur une liaison DB; 4 jointures internes sur   tables et 5 gauche se joint à grande ish sur   tables de taille moyenne.   ...   Toutes les tables dans la requête sont sur   le lien de base de données

Encore une fois, un trouble place potentiel. Si toutes les tables SELECT étaient de l'autre extrémité de la liaison DB, serait envoyé toute la requête à la base de données distante et le retour ResultSet. Une fois que vous lancez l'INSERT, il est plus probable que la base de données locale se chargera de la requête et tirer toutes les données des tables enfants plus. Mais cela peut dépendre si la vue est définie dans la base de données locale ou la base de données distante. Dans ce dernier cas, jusqu'à l'optimiseur local concerné il y a juste un objet distant et il obtient des données de cela, et la base de données distante fera la jointure.

Qu'est-ce qui se passe si vous allez simplement la télécommande DB et faire l'INSERT sur une table il?

Ceci est un bogue dans la gestion d'Oracle de jointures sur des liaisons DB. J'ai une situation plus simple qui ne comporte pas une instruction INSERT contre SELECT. Si je lance ma requête à distance, je reçois des lignes en double, mais si je l'exécuter localement, je ne sais pas. La seule différence entre les requêtes est le « @ ... » ajouté aux tables dans la requête à distance. J'Interrogation une base de données à partir d'une base de données 9i 10.2 en utilisant Oracle SQL Developer 3.0.

Ce encore plus stupide que ce bogue dans Oracle qui vous empêche de se joindre à des tables avec plus de 1000 colonnes au total, ce qui est très facile à faire lors de l'interrogation du système ERP. Et non, le message d'erreur est rien sur les tables ayant trop de colonnes.

Il est presque aussi stupide que l'autre bug de base de données Oracle qui interdit l'interrogation des tables contenant des localisateurs de LOB en utilisant la syntaxe ANSI. Seuls les travaux de syntaxe Oracle!

Plusieurs options me viennent.

  1. Les dupes que vous voyez étaient déjà dans la table de destination ??

  2. Si dans votre sélection, vous faites référence à la table que vous insérez dans, (?), Puis l'insert est en interaction avec la sélection dans votre combiné

    Insérer ... Sélectionner ... A partir de ...

De cette manière (produits cartésiens?) Pour créer les doublons

Je ne peux pas empêcher de penser que peut-être vous rencontrez un effet secondaire de quelque chose d'autre lié à la table. Y a-t-il des éléments déclencheurs qui peuvent être manipuler des données?

Comment avez-vous déterminé qu'il n'y a pas dupes dans le tableau original?

Comme d'autres l'ont noté cela semble être l'explication la plus simple de ce comportement étrange.

Vérifiez vos JOINs avec soin. Potentiellement vous avez pas de doublons dans les tables individuelles, mais peut causer des jointures underspecified CROSS JOINs afin que votre activation accidentelle jeu de résultats a des doublons en raison de la multiplicité et, lorsqu'elle est insérée, cela viole une contrainte d'unicité dans votre table de destination.

Ce que je fais dans ce cas est d'imbriquer la requête dans une vue ou CTE et essayer de détecter les doublons directement du SELECT:

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

Je vous conseille de prendre un plan sur la requête que vous utilisez et vous recherchez un CARTESIEN REJOIGNEZ là-dedans. Cela pourrait indiquer une condition manquante qui est à l'origine des lignes dupliquées.

AS @Pop a déjà suggéré ce comportement pourrait se produire si vous utilisez une connexion différente SQLPlus à la connexion lorsque votre insert est en cours d'exécution. (C'est si l'autre connexion a une table / view / synonyme du même nom)

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top