Exécuter plusieurs commandes SQL en un seul aller-retour

je suis en train de construire une application et je veux grouper plusieurs requêtes en un seul aller-retour vers la base de données. Par exemple, disons une page unique a besoin d'afficher une liste d'utilisateurs, une liste de groupes et une liste d'autorisations.

donc j'ai stocké des procs (ou juste des commandes sql simples comme" select * from Users"), et je veux en Exécuter trois. Cependant, pour peupler cette page je dois faire 3 voyages aller-retour.

maintenant je pourrais écrire un un seul proc stocké ("getUsersTeamsAndPermissions") ou exécuter une seule commande SQL"select * from Users;exec getTeams;select * from Permissions".

mais je me demandais s'il y avait une meilleure façon de préciser qu'il fallait effectuer trois opérations en un seul voyage aller-retour. Les avantages comprennent d'être plus facile à tester en unité, et de permettre au moteur de base de données de parralléliser les requêtes.

j'utilise C# 3.5 et SQL Server 2008.

27
demandé sur Patrick Karcher 2010-02-25 20:58:45

6 réponses

la commande multi-parties unique et les options de procédure stockées que vous mentionnez sont les deux options. Vous ne pouvez pas les faire de telle manière qu'ils soient "parallélisés" sur le db. Cependant, ces deux options donnent lieu à un aller simple , donc vous êtes bon là. Il n'y a aucun moyen de les envoyer plus efficacement. À partir de sql server 2005, une commande multi-pièces entièrement paramétrée est très efficace.

Edit : ajout d'informations sur les raisons pour lesquelles cram en un seul appel.

bien que vous ne vouliez pas trop vous soucier de réduire les appels, il peut être des raisons légitimes pour cela.

  • une fois, j'ai été limité à un conducteur boiteux D'ODBC contre un ordinateur central, et il y avait 1,2 seconde de trop à chaque appel! Je suis sérieuse. Il y a eu des moments où j'ai mis un peu de extra dans mes appels db. Pas assez.
  • vous pourriez également vous trouver dans une situation où vous devez configurer vos requêtes sql quelque part, et vous ne pouvez pas juste faire 3 appels: il doit être un. Ça ne devrait pas être comme ça, mauvais design, mais ça l'est. Tu fais ce que tu dois faire!
  • bien sûr, il peut parfois être très bon d'encapsuler plusieurs étapes dans une procédure stockée. Généralement pas pour économiser des voyages aller-retour, mais pour les transactions plus serrées, obtenir L'ID pour les nouveaux dossiers, contraignant pour permissions, fournir encapsulation, bla bla bla. ( mais s'il vous plaît ne pas commencer à utiliser des procédures stockées tout le temps. )
8
répondu Patrick Karcher 2017-05-23 11:54:48

quelque chose comme ce . L'exemple est probablement pas très bonne car elle ne permet pas d'éliminer correctement les objets, mais vous obtenez l'idée. Voici une version nettoyée:

using (var connection = new SqlConnection(ConnectionString))
using (var command = connection.CreateCommand())
{
    connection.Open();
    command.CommandText = "select id from test1; select id from test2";
    using (var reader = command.ExecuteReader())
    {
        do
        {
            while (reader.Read())
            {
                Console.WriteLine(reader.GetInt32(0));
            }
            Console.WriteLine("--next command--");
        } while (reader.NextResult());

    }
}
35
répondu Darin Dimitrov 2010-02-25 18:10:05

faire un aller-retour contre trois sera plus efficace en effet. La question est de savoir si cela en vaut la peine. L'ensemble ADO.Net et C # 3.5 ensemble d'outils et cadre s'oppose à ce que vous essayez de faire. TableAdapters, Linq2SQL, EF, tous ceux-ci aiment à traiter avec simple one-call==one-resultset sémantique. Ainsi, vous pouvez perdre une certaine productivité sérieuse en essayant de battre le cadre dans la soumission.

je dirais qu'à moins d'avoir un sérieux mesures montrant que vous nécessité de réduire le nombre d'allers-retours, s'abstenir. Si vous do finissez par l'exiger, alors utilisez une procédure stockée pour au moins donner une sorte D'API de sémantique.

, Mais si votre requête est vraiment ce que vous avez posté (ie. sélectionnez tous utilisateurs, toutes équipes et toutes permissions) alors vous avez évidemment beaucoup plus de poissons à frire avant de réduire les voyages aller-retour... réduisez d'abord les jeux de résultats.

2
répondu Remus Rusanu 2010-02-25 18:06:14

je suis ceci ce lien pourrait être utile.

envisager d'utiliser au moins la même connexion-l'ouverture; selon ce qu'il dit ici , l'ouverture d'une connexion est presque le chef de file du coût de performance dans Entity-Framework.

1
répondu Shimmy 2010-11-30 12:12:26

tout d'abord, 3 voyages aller-retour n'est pas vraiment une grosse affaire. Si vous parliez de 300 les voyages aller-retour alors ce serait une autre question, mais pour seulement 3 voyages aller-retour je considérerais cela pour definitley être un cas d'optimisation prématurée.

cela dit, la façon dont je ferais cela serait probablement d'exécuter les 3 procédures stockées en utilisant SQL:

exec dbo.p_myproc_1 @param_1 = @in_param_1, @param_2 = @in_param_2
exec dbo.p_myproc_2
exec dbo.p_myproc_3

vous pouvez alors itérer à travers le retour les ensembles de résultats comme vous le feriez si vous exécutiez directement plusieurs ensembles de rangées.

0
répondu Justin 2010-02-25 18:11:44

construire une table temporaire? Insérer tous les résultats dans la table de température et ensuite select * from @temp-table

comme dans,

@temptable=....
select @temptable.field=mytable.field from mytable
select @temptable.field2=mytable2.field2 from mytable2

etc... Une seule visite dans la base de données, même si Je ne suis pas sûr que ce soit plus efficace.

0
répondu Earlz 2010-02-25 18:16:45