Quelqu'un peut-il m'expliquer pourquoi la requête suivante retourne deux rangées et non seulement une? est-il correct que Oracle livre deux rangées? À mon avis, la ligne avec c1 = asdf ne devrait pas être dans le résultat. P> Voici une capture d'écran du résultat de la première requête: p>
3 Réponses :
Cela ressemble vraiment à un bug.
Je ne sais pas vraiment comment lire Expliquer les plans, mais ici c'est. Il me semble que le prédicat n'a été poussé à un seul des membres de l'Union et il a été transformé en "null n'est pas null" qui est totalement bizarre. P>
Notez que les chaînes pourraient être changées en "A "et" b '(donc nous n'utilisons pas de caractères spéciaux), l'Union et l'Union produisent tous le même bogue et que le bogue semble être déclenché par le max (somme (1)) dans la première branche; Il suffit de remplacer cela avec NULL ou autre chose qui est "simple", ou même avec la somme (1) (sans le max) provoque la fonction de fonctionner correctement. p>
ajouté strong>: étrangement, Si je change max (somme (1)) code> à
max (1) code> ou
somme (1) code> ou si je le changeai simplement à Le numéro littéral
1 code>, la requête fonctionne correctement - mais le plan d'explication montre toujours le même prédicat étrange, "Null n'est pas null". Donc, il semble que le problème est que le prédicat n'est pas poussé aux deux branches de l'Union, pas la transformation du prédicat. (Et même cela n'explique pas pourquoi
c2 code> apparaît comme
null code> dans la ligne supplémentaire de l'ensemble de résultats.) plus ajouté strong> (voir les commentaires ci-dessous ) - Comme il s'avère, le prédicat est poussé aux deux branches de l'Union, ce qui fait exactement ce qui cause le problème (comme Nicholas explique dans sa réponse). P>
Plan hash value: 1682090214
-------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 2 | 32 | 2 (0)| 00:00:01 |
| 1 | VIEW | | 2 | 32 | 2 (0)| 00:00:01 |
| 2 | UNION-ALL | | | | | |
| 3 | SORT AGGREGATE | | 1 | 2 | | |
| 4 | HASH GROUP BY | | 1 | 2 | | |
|* 5 | FILTER | | | | | |
| 6 | TABLE ACCESS FULL| DUAL | 1 | 2 | 2 (0)| 00:00:01 |
| 7 | FAST DUAL | | 1 | | 2 (0)| 00:00:01 |
-------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
5 - filter(NULL IS NOT NULL)
Avec juste max ou i> somme, poussez le prédicat dans la première branche ne reçoit aucune ligne; Avec max (somme (somme ()) code> Il reçoit une seule ligne avec NULL (vous pouvez exécuter cette autonome pour vérifier), ce qui est en soi juste (et est ce que Nicholas montre). Mais comme vous dites que poussez le prédicat dans la sous-requête semble tromper dans cette situation. Je suppose que l'optimiseur ne prend pas en compte les agrégats imbriqués lorsqu'il décide de le faire, ou quelque chose de ...
@Alexpoole - Je comprends cela de la réponse de Nicholas, et il fait un point parfaitement fin (je n'y ai pas pensé); Le seul désaccord que j'ai avec lui est qu'il indique que ce n'est pas un bug. (Je pense qu'il sera d'accord avec mon commentaire après qu'il l'ait dit cependant.)
Ouais, juste expliquer la partie "étrangement" - à moi-même quand j'ai commencé - ce qui a du sens; Le filtre impair a du sens dans ce contexte aussi, dans les deux cas.
@Alexpoole - Oh, j'ai relu ce que j'ai écrit, à la lumière de ce que Nicholas a expliqué. Ma spéculation est fausse - le prédicat est poussé aux deux branches, ce qui est exactement ce qui cause le problème! Je vais ajouter une note à ce sujet dans ma réponse.
@MathGuy @Alexpoole Une autre quirk est la façon dont vous obtenez des résultats différents lorsque vous exécutez SELECT * à partir de (SELECT 1 C1, max (SUMC (1)) C2 de Dual où NULL n'est pas NULL GROUPE PAR DMMY); CODE > VS
Sélectionnez 1 C1, max (somme (1)) C2 de Dual où NULL n'est pas un groupe NULL par factice; code>. L'étape du filtre est terminée durer dans l'ancien et plus tôt dans ce dernier (au moins, en 11.2.0.4). Wtf, optimiseur ?! * {;-)
[1] car de prédicat poussant votre sous-requête Fist renvoie sans rangées et lorsqu'une fonction d'agrégat (sauf Non Ce n'est pas un bug frappe>. Les fonctions globales sont la raison pour laquelle vous voyez ce résultat inattendu. Voici comment ça fonctionne. somme () code> fonction ainsi que
max () code> fonctionnera null (produisant 1 rangée) s'il n'y a pas de lignes retournées par la requête. Lorsque votre requête est exécutée Optimizer, l'optimiseur applique
PRINCIDE PRISHING CODE> Transformation et votre requête d'origine devient (ne postera pas la totalité de la trace, seule la requête transformée):
compte code> et peu d'autres),
max code> ou
somme code> ou même Comme dans ce cas, utilisé sur le jeu de résultats vide
null code> sera renvoyé - 1 rangée + 1 Retour par la deuxième sous-requête produisant ainsi un jeu de résultats de 2 lignes que vous regardez. P> < P> Voici une démonstration simple: p>
Vous venez d'expliquer que cette est B> un bug. Le prédicat de poussée ne doit pas être effectué avec un Union code> ou
Union tout code> s'il change le résultat. La requête a le prédicat dans la requête extérieure. Le poussant et produire un résultat différent est quelque chose qui ne va pas que l'optimiseur fait, c'est donc un bug. La requête elle-même n'a été ni demandée non pas prévue que le prédicat soit poussé.
@Mathguy C'est pourquoi j'ai dit que ce n'est pas un bug. Nous avons une vue en ligne avec Union code> Set opérateur, qui empêche l'affichage de la fusion (
Union [tout] empêche la fusion de la fusion non du prédicat de poussée code>) et l'optimiseur n'a pas d'autre choix mais poussez ce prédicat ( Le filtre Push Down Transformation a lieu). Nous pouvons empêcher le prédicat de pousser dans ce cas par "matérialisation" (en utilisant
matérialiser code> indice) qui affiche. Après avoir regardé un peu plus profondément dans cette ... Ouais, un mauvais résultat produit nous forçant à rechercher un travail autour. D'accord, ressemble à un bug.
Nous sommes d'accord ... dans ce que vous avez dit, l'optimiseur n'a pas d'autre choix que de pousser le prédicat "est la partie que nous serions en désaccord, car l'optimiseur a toujours le choix de laisser des prédicats seuls où ils sont. C'est dans le contrôle d'Oracle, la poussée des prédicats n'est pas requise par logique ni par les normes. Mais comme je l'ai dit, il est maintenant clair que nous sommes d'accord. À votre santé!
Un exemple beaucoup plus simple entraîne la même erreur:
SELECT 'ASDF' c1, MAX (SUM (1)) c2 FROM DUAL where 'ASDF' <> 'ASDF' GROUP BY dummy
Nicholas Krasnov a déjà expliqué pourquoi il est correct d'obtenir une seule ligne avec une valeur nulle de cette requête autonome. Le problème est que le filtre doit être appliqué plus tard dans le SCNARIO de l'OP, où l'agrégation est dans une sous-requête.
Pouvez-vous inclure le jeu de résultats?
Ne
groupe pas par mannequin code> provoque une erreur de syntaxe?
La capture d'écran de l'ensemble de résultats est incluse. Non, pas d'erreur de syntaxe - j'ai le problème aussi avec des tables réelles, je n'ai fait que l'échantillon aussi simple que possible.
Devinant Le caractère accentué favorise le type à une sorte de caractère large qui échoue par la suite du test contre ASCII
Non, il ne fonctionne pas non plus si j'utilise des chiffres: sélectionnez * à partir de (SELECT 1 C1, max (SUM (SUM (1)) C2 à partir du groupe DUMMY UNION SELECT 2 C1, 1 C2 de DUAL) Où C1! = 1;
@Gordonlinoff: Non, le tableau
Dual code> contient une seule colonne nommée
mannequin code>
Bogue. Notez également comment C2 est NULL B> et non 1 B>
@ Bernhard.Weingartner - Cela peut aider si vous modifiez votre message et changez les chaînes en «A» et «B» (et mettez-moi-même mettre à jour la sortie) - et peut-être aussi changer l'union à l'union tout - pour éviter plus de suppositions telles que celles ci-dessus.
Cela semble être causé par la nidification des agrégats - quelque chose d'autres DBMS rejeter quand même. Si vous remplacez
max (somme (1)) code> avec
somme (1) code> le fonctionnement fonctionne correctement.
@A_HORSE_WITH_NO_NAME - Je ne comprends pas ce point. Pourquoi aucun DBMS rejette cela? La somme (...) est pour chaque groupe (la requête a un groupe par clause). Ensuite, dans la sélection, vous pouvez agréger toutes les expressions de niveau de ligne (même si "rangée" est maintenant une ligne par groupe et l'expression est un agrégat de niveau de groupe). Le max est au niveau de la table complète. Alors pourquoi cela ne devrait-il pas être une expression valide?
@a_horse_with_no_name - Par exemple, je pense que c'est parfaitement bien, de trouver le salaire total maximum par département:
Sélectionnez max (SUM (SUM)) de Scott.emp groupe par DeptNo CODE> - Qu'est-ce qui ne va pas avec ça? Et, dans tous les cas, cela fonctionne parfaitement bien et renvoie le résultat correct, de sorte que cela ne explique que le bug Berhnard a rencontré.
@MathGuy: Probablement rien "faux", mais beaucoup d'autres SGM n'autorisent pas la nidification des agrégats comme celle-là (au moins SQL Server, Postgres et même MySQL).
Les DOCS disent explicitement que vous pouvez nier des fonctions agrégées . Comme cela semble être un bogue avec un prédicat poussant et des agrégats imbriqués, vous devriez soulever une demande de service avec Oracle. (Je ne vois rien d'évident sur MOS, et car il obtient le même résultat sur au moins 10 g-12c, il peut s'agir d'un nouveau scénario).
Je blâme
Dual code> et sa nature particulière. Reproduire cela sans elle.
lol @Phil - pourquoi tu ne fais-tu pas le travail? Créez une table et une requête et rapporte que vous n'avez pas vu le bogue dans cette configuration.