Question

J'utilise une requête SQL semblable au formulaire suivant:

SELECT col1, col2
FROM table1
LEFT OUTER JOIN table2
ON table1.person_uid = table2.person_uid
AND table1.period = table2.period

Et c'est soit trop lent, soit quelque chose d'impasse, car il faut au moins 4 minutes pour revenir. Si je devais le changer en ceci:

SELECT col1, col2
FROM table1
LEFT OUTER JOIN table2
ON table1.person_uid = table2.person_uid
WHERE table1.period = table2.period

alors cela fonctionne bien (bien que ne renvoyant pas le bon nombre de colonnes). Existe-t-il un moyen d’accélérer les choses?

UPDATE : la même chose est effectuée si je change les deux dernières lignes de la dernière requête:

SELECT col1, col2
FROM table1
LEFT OUTER JOIN table2
ON table1.period = table2.period
WHERE table1.person_uid = table2.person_uid

UPDATE 2: il s’agit en fait de vues que je rejoins. Malheureusement, ils ne figurent pas sur une base de données et ne peuvent donc pas (facilement) modifier l’indexation. Je suis enclin à convenir qu'il s'agit d'un problème d'indexation. J'attendrai un peu avant d'accepter une réponse au cas où il y aurait un moyen magique d'ajuster cette requête que je ne connais pas. Sinon, je vais accepter l'une des réponses actuelles et essayer de trouver un autre moyen de faire ce que je veux faire. Merci pour l'aide de tout le monde jusqu'à présent.

Était-ce utile?

La solution

N'oubliez pas que les énoncés 2 et 3 sont différents du premier.

Comment? Eh bien, vous faites une jointure externe gauche et votre clause WHERE n'en tient pas compte (comme le fait la clause ON). Au minimum, essayez:

SELECT col1, col2
FROM table1, table2
WHERE table1.person_uid = table2.person_uid (+)
AND table1.period = table2.period (+)

et voyez si vous rencontrez le même problème de performances.

Quels index avez-vous sur ces tables? Cette relation est-elle définie par une contrainte de clé étrangère?

Ce dont vous avez probablement besoin, c'est d'un index composite à la fois sur person_uid et sur period (sur les deux tables).

Autres conseils

Je pense que vous devez comprendre pourquoi les deux dernières ne sont pas la même requête que la première. Si vous faites une jointure gauche, puis ajoutez une clause where référençant un champ de la table du côté droit de la jointure (celle qui peut ne pas toujours avoir un enregistrement correspondant à la première table), alors vous avez effectivement changé la jointure en une jointure interne. Il y a une exception à cela: si vous faites référence à quelque chose comme

SELECT col1, col2
FROM table1
LEFT OUTER JOIN table2
ON table1.person_uid = table2.person_uid
WHERE table2.person_uid is null

Dans ce cas, vous demandez l’enregistrement qui n’a pas d’enregistrement dans le deuxième tableau. Mais à part ce cas particulier, vous modifiez la jointure gauche en une jointure interne si vous faites référence à un champ de la table2 dans la clause where.

Si votre requête n'est pas assez rapide, je regarderais votre indexation.

Ce que tout le monde vous dit en fonction des informations que vous avez fournies est une supposition.

Regardez le plan d'exécution de la requête. Si vous ne voyez pas de raison à la lenteur du plan, postez-le ici.

http://download.oracle .com / docs / cd / B28359_01 / server.111 / b28274 / ex_plan.htm # PFGRF009

Avez-vous des index de couverture sur personne_uid et période pour les deux tables?

Si ce n'est pas le cas, ajoutez-les et réessayez.

Examinez le plan d'exécution et voyez ce que fait réellement la requête.

Aussi: Quels sont les types de données des champs? Sont-ils les mêmes dans les deux tableaux? Une distribution implicite peut vraiment ralentir les choses.

Ces tables ont-elles des index sur les colonnes que vous rejoignez? Installez le produit gratuit SQLDeveloper d’Oracle et utilisez-le pour effectuer une opération "expliquer". sur cette requête et voir si il fait des analyses séquentielles des deux tables.

Dans une jointure gauche, vous scanneriez table1 pour chaque combinaison unique de (person_uid, period), puis recherchiez table2 pour tous les enregistrements correspondants. Si table2 ne possède pas d'index approprié, vous pouvez également analyser l'ensemble de cette table.

Ma meilleure hypothèse, sans voir de plan d'exécution, est que la première requête (la seule qui semble être correcte) a pour tâche d'analyser table table2 ainsi que table1.

Comme vous dites que vous ne pouvez pas modifier les index, vous devez modifier la requête. Autant que je sache, il n’existe qu’une seule alternative réaliste ...

SELECT
   col1, col2
FROM
   table2
FULL OUTER JOIN
   table1
      ON table1.person_uid = table2.person_uid
      AND table1.period = table2.period
WHERE
   table1.person_uid IS NOT NULL

Nous espérons ici que vous analysez table2 pour chaque combinaison unique de (personne_uid, période), mais que vous utilisez des index sur table1. (Contrairement à l'analyse de table1 et à l'utilisation d'index sur table2, ce à quoi je m'attendais de votre requête.)

Si table1 ne dispose pas d'index appropriés, il est toutefois très peu probable que vous constatiez une amélioration des performances ...

Dems.

Dans l'une des mises à jour, l'OP indique qu'il interroge en fait des vues et non des tables. Dans ce cas, les performances pourraient être améliorées en interrogeant directement les tables dont il a besoin, en particulier si les vues sont complexes et en se joignant à de nombreuses autres tables ne contenant pas les informations dont il a besoin ou qui appellent des vues.

La syntaxe de jointure ANSI établit une distinction très claire entre les conditions JOIN et les prédicats FILTER; c'est très important lorsque vous écrivez des jointures externes. À l'aide des tables emp / dept, examinez les résultats des deux jointures externes suivantes

Q1

SELECT dname, d.deptno, e.ename, e.mgr, d.loc
FROM dept d
LEFT OUTER JOIN emp e
on  d.deptno = e.deptno
and loc in ('NEW YORK','BOSTON' )
;

DNAME              DEPTNO ENAME             MGR LOC
-------------- ---------- ---------- ---------- -------------
ACCOUNTING             10 CLARK            7839 NEW YORK
ACCOUNTING             10 KING                  NEW YORK
ACCOUNTING             10 MILLER           7782 NEW YORK
RESEARCH               20                       DALLAS
SALES                  30                       CHICAGO
OPERATIONS             40                       BOSTON

====

Q2
SELECT dname, d.deptno, e.ename, e.mgr, d.loc
FROM dept d
LEFT OUTER JOIN emp e
on  d.deptno = e.deptno
where loc in ('NEW YORK','BOSTON' )
;

DNAME              DEPTNO ENAME             MGR LOC
-------------- ---------- ---------- ---------- -------------
ACCOUNTING             10 CLARK            7839 NEW YORK
ACCOUNTING             10 KING                  NEW YORK
ACCOUNTING             10 MILLER           7782 NEW YORK
OPERATIONS             40                       BOSTON

Le premier exemple présenté par Q1 est un exemple de "jonction à une constante". Essentiellement, la condition de filtre est appliquée avant d'effectuer la jointure externe. Vous éliminez donc les lignes, qui sont ensuite rajoutées dans la jointure externe. Ce n'est pas nécessairement faux, mais est-ce la requête que vous avez vraiment demandée? Ce sont souvent les résultats indiqués dans Q2 qui sont requis, où le filtre est appliqué après la jointure (externe).

Il existe également une implication en termes de performances, pour les grands ensembles de données. Dans de nombreux cas, l'optimiseur doit résoudre la jonction sur une constante de manière interne en créant une vue latérale qui ne peut généralement être optimisée que via une jointure de boucle imbriquée plutôt qu'une jointure de hachage

Pour les développeurs connaissant la syntaxe de jointure externe Oracle, la requête aurait probablement été écrite sous la forme

.
SELECT dname, d.deptno, e.ename, e.mgr, d.loc
FROM dept d
        ,emp e
where  d.deptno = e.deptno(+)
and loc in ('NEW YORK','BOSTON' )

Cette requête est sémantiquement équivalente à la Q2 ci-dessus.

En résumé, il est donc extrêmement important que vous compreniez la différence entre la clause JOIN et la clause WHERE lors de l'écriture de jointures externes ANSI.

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