J'écrivais mes chèques EXISTS comme ceci:
IF EXISTS (SELECT * FROM TABLE WHERE Columns=@Filters)
BEGIN
UPDATE TABLE SET ColumnsX=ValuesX WHERE Where Columns=@Filters
END
Un des DBA dans une vie précédente m'a dit que lorsque je fais une EXISTS
clause, utilisez SELECT 1
au lieu deSELECT *
IF EXISTS (SELECT 1 FROM TABLE WHERE Columns=@Filters)
BEGIN
UPDATE TABLE SET ColumnsX=ValuesX WHERE Columns=@Filters
END
Cela fait-il vraiment une différence?
sql
sql-server
tsql
Raj Plus
la source
la source
Réponses:
Non, SQL Server est intelligent et sait qu'il est utilisé pour un EXISTS et ne renvoie AUCUNE DONNÉE au système.
Quoth Microsoft: http://technet.microsoft.com/en-us/library/ms189259.aspx?ppud=4
Pour vous vérifier, essayez d'exécuter ce qui suit:
S'il faisait réellement quelque chose avec la liste SELECT, il lèverait une erreur div par zéro. Ce n'est pas le cas.
EDIT: Remarquez que le standard SQL en parle.
Norme ANSI SQL 1992, p. 191 http://www.contrib.andrew.cmu.edu/~shadow/sql/sql1992.txt
la source
EXISTS
astuce avec 1/0 peut même être étendue à celaSELECT 1 WHERE EXISTS(SELECT 1/0)
... semble un pas plus abstrait que le secondSELECT
n'a pas deFROM
clauseSELECT COUNT(*) WHERE EXISTS(SELECT 1/0)
. UnSELECT
sans unFROM
dans SQL Server est traité comme s'il accédait à une table à une seule ligne (par exemple, similaire à la sélection à partir de ladual
table dans d'autres SGBDR)SELECT
crée une table à 1 ligne avant de faire autre chose, même si1/0
la table à 1 ligne est toujours foutueEXISTS
?La raison de cette idée fausse est probablement due à la croyance que cela finira par lire toutes les colonnes. Il est facile de voir que ce n'est pas le cas.
Donne plan
Cela montre que SQL Server a pu utiliser l'index le plus étroit disponible pour vérifier le résultat malgré le fait que l'index n'inclut pas toutes les colonnes. L'accès à l'index se fait sous un opérateur de semi-jointure, ce qui signifie qu'il peut arrêter l'analyse dès que la première ligne est renvoyée.
Il est donc clair que la croyance ci-dessus est fausse.
Cependant, Conor Cunningham de l'équipe Optimiseur de requête explique ici qu'il utilise généralement
SELECT 1
dans ce cas, car cela peut faire une légère différence de performances dans la compilation de la requête.J'ai testé quatre façons possibles d'exprimer cette requête sur une table vide avec différents nombres de colonnes.
SELECT 1
vsSELECT *
vsSELECT Primary_Key
vsSELECT Other_Not_Null_Column
.J'ai exécuté les requêtes en boucle en utilisant
OPTION (RECOMPILE)
et mesuré le nombre moyen d'exécutions par seconde. Résultats ci-dessousComme on peut le voir, il n'y a pas de gagnant constant entre
SELECT 1
etSELECT *
et la différence entre les deux approches est négligeable. LesSELECT Not Null col
etSELECT PK
apparaissent cependant légèrement plus rapides.Les quatre requêtes se dégradent à mesure que le nombre de colonnes de la table augmente.
Comme le tableau est vide, cette relation ne semble explicable que par la quantité de métadonnées de colonne. Car
COUNT(1)
il est facile de voir que cela est réécritCOUNT(*)
à un moment donné du processus par le bas.Ce qui donne le plan suivant
Attacher un débogueur au processus SQL Server et interrompre aléatoirement lors de l'exécution de ce qui suit
J'ai trouvé que dans les cas où la table contient 1024 colonnes la plupart du temps, la pile d'appels ressemble à quelque chose comme ci-dessous, indiquant qu'elle passe effectivement une grande partie du temps à charger les métadonnées de la colonne même lorsqu'elle
SELECT 1
est utilisée (dans le cas où le la table a 1 colonne au hasard, la rupture n'a pas atteint ce bit de la pile d'appels en 10 tentatives)Cette tentative de profilage manuel est sauvegardée par le profileur de code VS 2012 qui montre une sélection très différente de fonctions consommant le temps de compilation pour les deux cas ( Top 15 Functions 1024 colonnes vs Top 15 Functions 1 colonne ).
Les versions
SELECT 1
etSELECT *
finissent par vérifier les autorisations de colonne et échouent si l'utilisateur n'a pas accès à toutes les colonnes de la table.Un exemple que j'ai cribbed d'une conversation sur le tas
On pourrait donc supposer que la différence apparente mineure lors de l'utilisation
SELECT some_not_null_col
est qu'elle ne vérifie que les autorisations sur cette colonne spécifique (bien qu'elle charge toujours les métadonnées pour tous). Cependant, cela ne semble pas correspondre aux faits, car la différence de pourcentage entre les deux approches se réduit si le nombre de colonnes dans le tableau sous-jacent augmente.Dans tous les cas, je ne me précipiterai pas et ne changerai pas toutes mes requêtes sous cette forme car la différence est très mineure et n'apparaîtra que lors de la compilation des requêtes. La suppression du
OPTION (RECOMPILE)
afin que les exécutions ultérieures puissent utiliser un plan mis en cache a donné ce qui suit.Le script de test que j'ai utilisé peut être trouvé ici
la source
Le meilleur moyen de le savoir est de tester les performances des deux versions et de consulter le plan d'exécution des deux versions. Choisissez une table avec beaucoup de colonnes.
la source
Il n'y a aucune différence dans SQL Server et cela n'a jamais posé de problème dans SQL Server. L'optimiseur sait qu'ils sont identiques. Si vous regardez les plans d'exécution, vous verrez qu'ils sont identiques.
la source
Personnellement, je trouve très, très difficile de croire qu'ils n'optimisent pas le même plan de requête. Mais la seule façon de savoir dans votre situation particulière est de la tester. Si vous le faites, veuillez faire un rapport!
la source
Pas de réelle différence mais il pourrait y avoir un très petit impact sur les performances. En règle générale, vous ne devriez pas demander plus de données que ce dont vous avez besoin.
la source