J'ai besoin d'écrire une requête pour récupérer une grande liste d'identifiants.
Nous prenons en charge de nombreux backends (MySQL, Firebird, SQLServer, Oracle, PostgreSQL ...) donc j'ai besoin d'écrire un SQL standard.
La taille de l'ensemble d'identifiants pourrait être importante, la requête serait générée par programme. Alors, quelle est la meilleure approche?
1) Ecrire une requête en utilisant IN
SELECT * FROM TABLE WHERE ID IN (id1, id2, ..., idn)
Ma question est ici. Que se passe-t-il si n est très grand? Et qu'en est-il des performances?
2) Ecrire une requête en utilisant OU
SELECT * FROM TABLE WHERE ID = id1 OR ID = id2 OR ... OR ID = idn
Je pense que cette approche n'a pas de limite n, mais qu'en est-il des performances si n est très grand?
3) Rédaction d'une solution programmatique:
foreach (var id in myIdList)
{
var item = GetItemByQuery("SELECT * FROM TABLE WHERE ID = " + id);
myObjectList.Add(item);
}
Nous avons rencontré des problèmes avec cette approche lorsque le serveur de base de données est interrogé sur le réseau. Normalement, il est préférable de faire une seule requête qui récupère tous les résultats plutôt que de faire beaucoup de petites requêtes. J'ai peut-être tort.
Quelle serait la bonne solution à ce problème?
IN
! J'ai fait le mien comme votre solution 1 + 3. Juste la requête finale était une longue chaîne de requête envoyée à SQL pour s'exécuter.Réponses:
L'option 1 est la seule bonne solution.
Pourquoi?
L'option 2 fait la même chose mais vous répétez le nom de la colonne plusieurs fois; en outre, le moteur SQL ne sait pas immédiatement que vous souhaitez vérifier si la valeur est l'une des valeurs d'une liste fixe. Cependant, un bon moteur SQL pourrait l'optimiser pour avoir des performances égales comme avec
IN
. Il y a cependant toujours un problème de lisibilité ...L'option 3 est tout simplement horrible en termes de performances. Il envoie une requête à chaque boucle et martèle la base de données avec de petites requêtes. Cela l'empêche également d'utiliser les optimisations pour "la valeur est l'une de celles d'une liste donnée"
la source
Une autre approche pourrait être d'utiliser une autre table pour contenir les valeurs d'identifiant. Cette autre table peut ensuite être jointe en interne sur votre TABLE pour contraindre les lignes renvoyées. Cela aura l'avantage majeur que vous n'aurez pas besoin de SQL dynamique (problématique dans le meilleur des cas), et vous n'aurez pas une clause IN infiniment longue.
Vous pourriez tronquer cette autre table, insérer votre grand nombre de lignes, puis peut-être créer un index pour faciliter les performances de jointure. Cela vous permettrait également de dissocier l'accumulation de ces lignes de la récupération des données, vous donnant peut-être plus d'options pour régler les performances.
Mise à jour : Bien que vous puissiez utiliser une table temporaire, je ne voulais pas dire que vous devez ou même devriez. Une table permanente utilisée pour les données temporaires est une solution courante avec des avantages au-delà de ceux décrits ici.
la source
select
instruction sur une autre table. La liste est transmise comme l'autre table à laquelle vous vousinner join
opposez.Ce que Ed Guiness a suggéré est vraiment un booster de performances, j'avais une requête comme celle-ci
ce que j'ai fait :
Ensuite, l'intérieur a rejoint la température avec la table principale:
Et les performances se sont considérablement améliorées.
la source
La première option est certainement la meilleure option.
Cependant, étant donné que la liste des identifiants est très énorme , disons des millions, vous devriez considérer des tailles de bloc comme ci-dessous:
Pourquoi devriez-vous diviser en morceaux?
Cela a toujours fonctionné comme du charme pour moi. J'espère que cela fonctionnerait aussi pour mes collègues développeurs :)
la source
L'exécution de la commande SELECT * FROM MyTable où id in () sur une table Azure SQL avec 500 millions d'enregistrements a entraîné un temps d'attente> 7min!
Faire cela à la place a renvoyé des résultats immédiatement:
Utilisez une jointure.
la source
Dans la plupart des systèmes de base de données,
IN (val1, val2, …)
et une série deOR
sont optimisés selon le même plan.La troisième façon serait d'importer la liste de valeurs dans une table temporaire et de la joindre, ce qui est plus efficace dans la plupart des systèmes, s'il y a beaucoup de valeurs.
Vous voudrez peut-être lire ces articles:
la source
L'échantillon 3 serait le moins performant de tous, car vous consultez la base de données d'innombrables fois sans raison apparente.
Charger les données dans une table temporaire, puis les rejoindre serait de loin le plus rapide. Après cela, le IN devrait fonctionner un peu plus vite que le groupe des OR.
la source
Je pense que vous voulez dire SqlServer mais sur Oracle, vous avez une limite stricte du nombre d'éléments IN que vous pouvez spécifier: 1000.
la source