10
votes

Pourquoi SP_EXecutesQL fonctionne-t-il plus lentement lorsque des paramètres sont transmis comme des arguments

Query 1: (foudre rapide) xxx

vs.

requête 2: (trop lent) xxx < p> TableView - une vue contenant plusieurs jointures

linq convertit toujours des requêtes en forme de requête2 et donc la performance est vraiment mauvaise.

questions: j'ai besoin de la raison Pour la lenteur de Query2, et toute résolution s'il y en a un. Et une résolution pour Linq.

---- supplément de commentaires:

Le coup de performance est définitivement à cause des 2 colonnes qui utilisent des fonctions de classement (Row_Number) mais je ne peux pas les éviter que j'en ai besoin.


11 commentaires

Avez-vous beaucoup de lignes avec id = 1?


@Lasse, même si j'ai 50 enregistrements, la différence est énorme. Comme 0 sec vs 10 sec, une chose est sélectionnée * à partir de la table, est généralement une vue avec beaucoup de jointures.


Quel est le type de données transmis pour @ID ? Vous pouvez avoir une moulage implicite pour empêcher l'utilisation d'un index.


Je ne peux pas dire si cela répondit ma question ou si vous l'avez dit "Même si j'ai 50 rangées au total dans ma table ...". Avez-vous beaucoup de lignes avec id = 1. C'est une question oui ou non, ni éventuellement "qu'est-ce que tu veux dire par" beaucoup "". De toute façon ... Avez-vous beaucoup de lignes avec id = 1?


Vous devriez être capable de regarder les plans de requête et de voir s'il y a une différence. Dans le premier cas, il peut être en mesure d'effectuer une optimisation. Mais évidemment, il y aurait des frais généraux pour le remplacement des paramètres.


@Lasse Tables pourrait être énorme, mais les enregistrements contre ID = 1 pourraient être 50, 100 de cette gamme. Même alors son lent.


@Whoisninja - Mais quel est le type de données déclaré dans le sp_executeql appel?


@Whoisninja - Ah Droite. Vous avez probablement un problème de reniflement du paramètre alors. Le plan paramétré aura été compilé en fonction de la valeur d'abord passée pour @ID , qui peut avoir été considérablement plus (ou moins) sélective que 1 est. Le plan compilé pour cette valeur peut ne pas convenir aux autres.


@Martin, quel paramètre wniffing est-il?


@Martin, j'essaie de lire sur Internet à ce sujet, mais de toute résolution?


@Whoisninja - Les résolutions habituelles doivent utiliser des allembles de requête telles que optimiser pour ou recompiler . Je ne sais pas comment faire cela de Linq cependant.


3 Réponses :


0
votes
  1. Évitez d'utiliser SELECT *
  2. ado.net 3.5 Il y a "QUESTING DE PARAMÈTRE" dans LINQ 1 = TINYINT 2345 = Smallint 76357242 = INT .. Dans ADO.NET 4.0 PARAMETER QUESSING est remplacé par défaut Int Type de données 1 = int, 2335 = int, 76357242 = INT)

1 commentaires

Je n'utilise jamais Select *, c'était juste par exemple.



7
votes

Je vais sortir sur un membre ici et supposer que vous avez beaucoup de lignes où id = 1.

sinon, corrigez-moi s'il vous plaît.

une raison possible que SQL Le serveur traite votre requête lente est qu'il regarde la requête et va:

hmm, je me demande ce qu'il va passer pour ce paramètre.
Est-ce que ça va être 1? Où j'ai sur les lignes de Gazillion?
ou peut-être 1742, où je n'ai que 3
Je ne sais tout simplement pas, je ferais mieux de faire une analyse de table pour être sûr de produire un plan d'exécution qui couvrira toutes mes bases

Si une colonne ou une colonne définie, la sélectivité est faible (c.-à-d. Le nombre de valeurs uniques est beaucoup moins que le nombre de lignes), SQL Server reviendra parfois à une tablette ou similaire, juste pour Obtenez toutes les lignes déterminées.

au moins cela a été mon expérience. En particulier, j'ai vu le même comportement lorsque la plage de la date sélectionne sur des tableaux avec des données liées à temps, effectuez un où dt <= @dt et dt> = @DT Pour obtenir toutes les lignes où @DT est à l'intérieur d'une période de temps dans cette rangée, revient à une table-balayage, puis lorsque je place la date réelle dans le SQL comme littéral, il fonctionne bien plus vite.

Le problème ici est la sélectivité, SQL Server ne sait pas comment mieux répondre à tous les scénarios lors de la construction d'un plan d'exécution pour votre relevé, il essaierai donc de deviner.

Essayez d'ajouter une indication de requête pour spécifier un typique < / em> valeur pour le paramètre, à savoir.: xxx


4 commentaires

Optimiser pour ne pas aider, je ne peux pas demander à Linq d'ajouter optimiser à l'intérieur de la requête qu'elle construit. :(


Et en parlant d'enregistrements, il y aura des millions d'enregistrements renvoyés s'il n'ya pas de clause où la clause de cette requête, car la vue contient des jointures entre d'énormes tables.


1. Qui a dit quelque chose à propos de "NO OSLLES CLAUSE"? et 2. Avez-vous essayé d'exécuter le SQL avec une optimisation de la clause et de regarder les différences? et 3) ... est un orj qui ne connaît pas vos données toujours la meilleure approche?


Encore une autre raison pour laquelle utiliser un ormes n'est pas toujours un bon choix.



2
votes

Ceci pourrait être un paramètre reniflant problème. Essayez d'inclure la ligne: xxx

à la fin de votre requête SQL.

Il existe un article ici expliquant ici quel paramètre renifler est: http://blogs.technet.com/b/mdegre/archive /2012/03/19/what-is-parameter-sniffing.aspx


1 commentaires

Bien que je ne puisse pas utiliser cela directement, c'était la réponse à mon problème, à savoir que les paramètres causaient des analyses de table au lieu d'utiliser des index. L'utilisation de l'option (recompiler) a forcé la vision sous-jacente à utiliser un plan utilisant des utilisations des index de table. Malheureusement, je ne pouvais pas utiliser cela car mon analyseur SQL Middleware ne peut pas accepter la syntaxe. Ma solution de contournement était de construire le SQL sans les paramètres, de coder efficacement les valeurs dans la requête. Pas d'idéal, mais cela évitait la requête étant transformée en sp_executesql.