J'ai deux tables institutions et résultats et je souhaite voir s'il y a des résultats pour des institutions de la manière dont je peux exclure ceux qui n'ont pas de résultats.
Puis-je obtenir de meilleures performances en utilisant une jointure ou une utilisation existante?
Merci,
[.____] - Nimesh
Selon la déclaration, les statistiques et le serveur DB, il peut ne pas faire de différence - le même plan de requête optimisé peut être produit.
Il y a essentiellement 3 façons que DBS rejoignez des tables sous le capot:
Boucle imbriquée - pour une table beaucoup plus grande que la seconde. Chaque rangée dans la table la plus petite est vérifiée pour chaque rangée dans le plus grand.
Fusionner - pour deux tables dans le même ordre de tri. Les deux sont courus dans l'ordre et sont assortis là où ils correspondent.
Hachage - tout le reste. Les tables temporaires sont utilisées pour constituer les matchs.
En utilisant des existes, vous risquez de forcer efficacement le plan de requête à faire une boucle imbriquée. Cela peut être le moyen le plus rapide, mais vous voulez vraiment que le planificateur de requête décidera.
Je dirais que vous devez écrire à la fois des déclarations SQL et comparer les plans de requête. Vous trouverez peut-être qu'ils changent assez malgré les données que vous avez.
Par exemple, si [institutions] et [Résultats] sont des tailles similaires et les deux sont regroupées sur l'établissement, une jointure de fusion serait la plus rapide. Si [résultats] est beaucoup plus gros que [institutions] une boucle imbriquée peut être plus rapide.
Ça dépend.
En fin de compte, les 2 servent de manière totalement différente.
Vous rejoignez 2 tables pour accéder aux enregistrements associés. Si vous n'avez pas besoin d'accéder aux données des enregistrements associés, vous n'avez pas besoin de les rejoindre.
Il existe peut être utilisé pour déterminer si un jeton existe dans un jeu de données donné, mais ne vous permettra pas d'accéder aux enregistrements associés.
Publiez un exemple des 2 méthodes que vous avez à l'esprit et je pourrais peut-être vous donner une meilleure idée.
Avec vos deux tableaux et vos résultats si vous souhaitez une liste d'institutions ayant des résultats, cette requête sera plus efficace:
select Institutions.institution_name
from Institutions
inner join Results on (Institutions.institution_id = Results.institution_id)
Si vous avez une institution_id et que vous voulez juste savoir s'il a des résultats, l'utilisation d'exists peut être plus rapide:
if exists(select 1 from Results where institution_id = 2)
print "institution_id 2 has results"
else
print "institution_id 2 does not have results"
Cela dépend de votre optimiseur. J'ai essayé les deux ci-dessous dans Oracle 10g et 11g. En 10g, le second était légèrement plus rapide. En 11g, ils étaient identiques.
Cependant, # 1 est vraiment une mauvaise utilisation de la clause existante. Utilisez des jointures pour trouver des allumettes.
select *
from
table_one t1
where exists (
select *
from table_two t2
where t2.id_field = t1.id_field
)
order by t1.id_field desc
select t1.*
from
table_one t1
,table_two t2
where t1.id_field = t2.id_field
order by t1.id_field desc
Qu'il s'agisse d'une différence de performance ou non, vous devez utiliser ce qui est plus approprié pour votre objectif. Votre objectif est d'obtenir une liste d'institutions (pas de résultats - vous n'avez pas besoin de données supplémentaires). Alors sélectionnez des institutions qui n'ont aucun résultat ... la traduction - l'utilisation existe.
Je dirais que la jointure est plus lente, car votre exécution de requête s'arrête dès qu'un appel existant trouve quelque chose, alors qu'une jointure continuera jusqu'à la fin.
Edit: Mais cela dépend de la requête. C'est quelque chose qui devrait être jugé au cas par cas.
Utilisez-vous existe-t-il dans le cadre d'une sous-requête corrélée? Si tel est le cas, la jointure sera presque toujours plus rapide.
Votre base de données devrait avoir des moyens de comparer des requêtes. Utilisez-les pour voir quelle requête fonctionne plus vite.
Une jointure extérieure gauche aura tendance à fonctionner mieux qu'aucun n'existe pas **, mais dans votre cas, vous voulez faire exister et utiliser une simple join interne ne reproduit pas exactement le comportement existant. Si vous avez de multiples résultats pour une institution, faire la join interne retournera plusieurs rangées pour cette institution. Vous pouvez vous contourner cela en utilisant des distincts, mais ils seront probablement mieux pour la performance de toute façon.
** Pour ceux qui ne sont pas familiers avec cette méthode:
SELECT
MyTable.MyTableID
FROM
dbo.MyTable T1
LEFT OUTER JOIN dbo.MyOtherTable T2 ON
T2.MyTableID = T1.MyTableID
WHERE
T2.MyOtherTableID IS NULL
est équivalent à
SELECT
MyTable.MyTableID
FROM
dbo.MyTable T1
WHERE NOT EXISTS (SELECT * FROM MyOtherTable T2 WHERE T2.MyTableID = T1.MyTableID)
en supposant que la myothableID soit une colonne NON NULLL. La première méthode fonctionne généralement plus rapidement que la méthode ne pas exister cependant.
Dans des cas comme au-dessus de la déclaration existante fonctionne plus rapidement que celui des jointures. Existe vous donnera un enregistrement unique et sauvera également le temps. En cas de jointures, le nombre d'enregistrements sera davantage et que tous les enregistrements doivent être utilisés.
Si la table des résultats a plus d'une ligne par INSTITUTION
, EXISTS()
a l'avantage supplémentaire de ne pas vous obliger à sélectionner des institutions distinctes.
En ce qui concerne la performance, j'ai vu joins, IN(), and EXISTS()
chacun soit le plus rapide de diverses utilisations. Pour trouver la meilleure méthode à vos fonctions, vous devez tester.
En fait, de votre description vague du problème, cela me semble que comme une requête n'est pas la voie la plus évidente de la coder:
SELECT *
FROM Institutions
WHERE InstitutionID NOT IN (
SELECT DISTINCT InstitutionID
FROM Results
)
Si vous souhaitez que les institutions n'ayant pas eu de résultats, une sous-requête "où il n'existe pas" sera plus rapide, car elle s'arrêtera dès qu'il trouve un seul résultat pour ceux qui ont des résultats ...
Si vous voulez les institutions avec des résultats, mais vous ne voulez pas réellement les résultats, même chose. Utilisez un "où existe-t-il". Il s'arrêtera dès qu'il trouve un seul résultat ... Cela garantit également que l'ensemble de résultats n'aura qu'un seul enregistrement par établissement, alors que si vous aviez une institution avec plusieurs résultats, en utilisant le Une approche de jointure nécessiterait que vous ajoutez le mot-clé "Distinct" ou une clause "Groupe par" pour éliminer les lignes de produit de la cartésion en double qui ferait prodiguée des enregistrements de résultat multiples correspondant à une seule inscription.
Si vous avez besoin des résultats, faites une jointure - une jointure intérieure si vous ne voulez pas voir les informations sans résultat et une jointure extérieure Si vous souhaitez voir toutes les institutions, y compris celles sans résultats.
Si vous faites référence à l'utilisation d'une jointure extérieure gauche (ou droite) ou d'une sous-requête, je suis assez certain que le join extérieur gauche remporte la performance. Par exemple:
SELECT t1.* FROM table1 t1 LEFT OUTER JOIN table2 t2 ON t1.id = t2.id WHERE t2.id IS NULL
Ce qui précède devrait être plus rapide que la sous-requête équivalente, et si vous vous référez spécifiquement à des exergences - Eh bien, où la structure permet, une jointure interne sera toujours l'option préférée.