7
votes

Comment éviter la même sous-requête dans plusieurs sélectionner dans Oracle?

Il s'agit de trois sélectionnes différentes en utilisant la même sous-requête. Comment puis-je utiliser le résultat de la sous-requête au lieu de faire une sous-requête à nouveau.

SELECT  *
FROM    Address
WHERE   address_key IN
        (
        SELECT  address_key
        FROM    person_address
        WHERE   peson_key IN (person_list)
        );   -- person_list := '1,2,3,4'

SELECT  *
FROM    Phone 
WHERE   phone_key IN
        (
        SELECT  address_key
        FROM    person_address
        WHERE   peson_key IN (person_list)
        );

SELECT  *
FROM    Email
WHERE   address_key IN
        (
        SELECT  address_key
        FROM    person_address
        WHERE   peson_key IN (person_list)
        );


0 commentaires

3 Réponses :


6
votes

Vous pouvez créer une vue matérialisée pour cette requête: xxx

ou créer une table temporaire et le peupler: xxx

, Mais, vraiment, si vous indexez votre person_key , il est correct pour réutiliser la sous-requête.

puisque vous avez 3 des requêtes distinctes, vous avez besoin de vos valeurs à être visible à une manière ou une autre.

Cela signifie que vous devez stocker ces valeurs quelque part, que ce soit la mémoire, la mémoire temporaire ou un espace de table permanent.

mais les valeurs dont vous avez besoin sont déjà stocké dans le person_address , tout ce dont vous avez besoin est de les récupérer.

Utilisation de la sous-requête 3 impliquera 12 Index scans pour aller chercher le Rowid S de l'index sur Person_Key et 12 Table Rowid Recherche pour aller chercher adresse_key de la table. Ensuite, très probablement une table de hachage sera construite sur eux.

Il s'agit d'une question de microsecondes.

Bien sûr, la table temporaire ou une vue matérialisée serait un peu plus efficace, mais changer le temps de sous-requête de 100 microsecondes vers 50 en vaut la peine, à condition que les requêtes principales puissent prendre des minutes. < / p>


1 commentaires

+1 ou l'idée GTT - surtout si la logique de remplissage est plus compliquée ou prend du temps que dans l'exemple ici.



8
votes

Utilisez la clause avec la clause. Je n'ai pas ré-créé votre problème exemplaire exact, mais un nombre quelconque de sous-requêtes répétées peut être placée dans la clause avec puis référencée dans la requête.

WITH  address_keys as (
        SELECT  address_key
        FROM    person_address
        WHERE   peson_key IN (person_list)
        )
Select * from table1, table2, address_keys
where table1.address_key = address_keys.address_key
and table2.address_key = address_keys.address_key


3 commentaires

Avec ne renvoie pas trois ensembles de résultats comme je le souhaite. La vue créée avec la clause ne peut être utilisée que dans une requête non multiple. Je serais peut-être en train de manquer quelque chose.


Je pense que le point de Brian est de ne pas courir trois requêtes - courir une requête de l'union tous ensemble. Ce sera plus efficace de cette façon.


Bien sûr, si les trois résultats se déroule ont des motifs extrêmement différents, cela ne vous aidera peut-être pas :)



4
votes

Tout d'abord, je pense que dans la plupart des cas, cette optimisation n'apporte pas d'améliorations significatives (après la première requête que les blocs de données de Person_Address seraient principalement mis en cache dans le cache tampon et donc non lus à partir du disque dur).

Cependant comme un cas étude ou pour une raison quelconque: Vous devez mettre en cache les résultats de la requête répétée et les réutiliser plus tard dans 3 sélectionne. Cela peut être réalisé par une table (Temp) ou MV ou une structure de plsql Varray.

Les deux premières options couvrent Quassnoi dans sa réponse, donc je ne les mentionnerai pas. Le troisième est désavantage pour indiquer à l'avance le nombre maximal de lignes à l'avance (et je ne sais pas le droit de savoir ce qui se passe lorsque vous déclarez une varrayne avec la limite supérieure de 1 m ou 1 g d'articles seulement si vous n'avez besoin que de 1k). xxx


0 commentaires