Bon, mauvais ou indifférent: O 1 1 = 1

14

Compte tenu de cette question sur reddit, j'ai nettoyé la requête pour indiquer où se trouvait le problème dans la requête. J'utilise d'abord des virgules et WHERE 1=1pour faciliter la modification des requêtes, mes requêtes se terminent généralement comme suit:

SELECT 
     C.CompanyName
    ,O.ShippedDate
    ,OD.UnitPrice
    ,P.ProductName
FROM 
               Customers       as C
    INNER JOIN Orders          as O  ON C.CustomerID = O.CustomerID
    INNER JOIN [Order Details] as OD ON O.OrderID    = OD.OrderID
    INNER JOIN Products        as P  ON P.ProductID  = OD.ProductID
Where 1=1
--  AND O.ShippedDate Between '4/1/2008' And '4/30/2008'
    And P.productname = 'TOFU'
Order By C.CompanyName

Quelqu'un a essentiellement dit que 1 = 1 est généralement paresseux et mauvais pour les performances .

Étant donné que je ne veux pas "optimiser prématurément" - je veux suivre les bonnes pratiques. J'ai déjà examiné les plans de requête, mais généralement uniquement pour savoir quels index je peux ajouter (ou ajuster) pour accélérer l'exécution de mes requêtes.

La question est alors vraiment ... de Where 1=1provoquer de mauvaises choses? Et si oui, comment savoir?

Édition mineure: j'ai toujours `` supposé '' que ce 1=1serait optimisé, ou au pire négligeable. Ne fait jamais de mal à remettre en question un mantra, comme "Goto's are Evil" ou "Premature Optimization ..." ou d'autres faits supposés. Je ne savais pas si 1=1 ANDcela affecterait ou non les plans de requête de manière réaliste. Et dans les sous-requêtes? CTE? Procédures?

Je ne suis pas du genre à optimiser, sauf si c'est nécessaire ... mais si je fais quelque chose qui est réellement "mauvais", je voudrais minimiser les effets ou changer le cas échéant.

WernerCD
la source
2
Non, ce ne serait pas le cas. Mis à part quelques microsecondes pour que l'optimiseur supprime la condition redondante. Vous feriez mieux de vous concentrer sur le fait que vos littéraux de date ne soient pas ambigus.
ypercubeᵀᴹ
Comme l'a dit @ypercube, cela ne fait aucune différence. L'optimiseur de requêtes devrait être un morceau de **** pour qu'une telle chose fasse une différence;)
Philᵀᴹ
4
Ne croyez pas tout ce que vous lisez sur reddit. S'il vous plaît.
Aaron Bertrand
1
@AaronBertrand Je prends tout avec un grain de sel, jusqu'à ce que j'en fasse l'expérience de première main. Je vais quand même prendre une question qui semble plausible et voir s'il y a du vrai, surtout quand cela affecte mon travail quotidien.
WernerCD
4
Il y a des grains de sel, puis la teneur en sel d'un océan entier déversé au-dessus de votre immeuble de bureaux: P
Philᵀᴹ

Réponses:

13

Le serveur SQL analyseurL'optimiseur a une fonction appelée "Pliage constant" qui élimine les expressions tautologiques de la requête.
Si vous regardez le plan d'exécution, nulle part dans les prédicats, vous ne verrez cette expression apparaître. Cela implique que le pliage constant est effectué de toute façon au moment de la compilation pour cela et pour d'autres raisons et cela n'a aucun effet sur les performances des requêtes.

Voir Évaluation du pliage constant et de l'expression pendant l'estimation de la cardinalité pour plus d'informations.

spaghettidba
la source
Il est probablement compilé car il s'agit d'un modèle connu pour effectuer la concaténation de champs.
jcolebrand
Non, il est compilé car il est tautologique. Cela fonctionnerait de la même manière avec 2736 = 2736, ce qui n'est pas aussi habituel que 1 = 1. Il en va de même pour les contradictions. Dans ce cas, la fonction est appelée "Détection de contradiction".
spaghettidba
Quelle partie du «motif connu» signifiait «doit être 1 = 1»?
jcolebrand
9

L'ajout du prédicat redondant peut faire une différence dans SQL Server.

Dans les plans d'exécution ci-dessous, notez le @1dans le premier plan par rapport au littéral 'foo'dans le deuxième plan.

entrez la description de l'image ici

Cela indique que SQL Server a considéré la première requête de paramétrage simple pour promouvoir la réutilisation du plan d'exécution - cependant la comparaison de deux constantes empêche cela de se produire dans le second cas.

Une liste de conditions qui empêchent le paramétrage simple (anciennement connu sous le nom de paramétrisation automatique) se trouve à l'annexe A des plans techniques de mise en cache de Microsoft:

le paramétrage simple n'est généralement pas quelque chose sur lequel vous devriez compter de toute façon. Il est préférable de paramétrer explicitement vos requêtes.

Martin Smith
la source
4

Dans tout SGBDR moderne (y compris Oracle, Microsoft SQL Server et PostgreSQL - j'en suis sûr), cela n'aura aucun effet sur les performances.

Comme quelqu'un l'a noté, cela n'affectera que la phase de planification des requêtes. Par conséquent, la différence ne sera visible que lorsque vous exécutez des milliers d'itérations d'une requête simpliste qui ne renvoie aucune donnée, comme celle-ci:

SELECT 1 FROM empty_table; -- run this 10 000 times.

SELECT 1 FROM empty_table WHERE 1=1; -- run this 10 000 times and compare.

Pour moi, sur PostgreSQL 9.0, cela est visible avec seulement 10000 itérations:

filip@srv:~$ pgquerybench.pl -h /var/run/postgresql/ -q "select 1 from never where 1=1" -q "select 1 from never" -i 10000
Iterations: 10000
Query:   select 1 from never where 1=1
Total:   2.952 s
Average: 0.295 ms
Query:   select 1 from never
Total:   2.850 s
Average: 0.285 ms
filiprem
la source
0

Cela peut être un "problème" pour Oracle lorsque vous utilisez le paramètre de base de données cursor_sharing. Lorsque ce paramètre est défini sur "forcer", il modifie toutes les instructions SQL. Toutes les "constantes" des requêtes seront remplacées par des variables de liaison (comme 1 =>: SYS_0).

Cette option a été introduite pour gérer certains développeurs paresseux. D'un autre côté, cela peut également nuire à d'autres développeurs paresseux. Mais le risque n'est pas trop élevé. Depuis 11g, il a une fonction de furtivité variable.

ibre5041
la source
Pouvez-vous clarifier ce que "depuis la version 11g, il a une fonction de lecture variable". veux dire?
ypercubeᵀᴹ
@ypercube "Bind variable peeking" signifie que l'optimiseur observera les valeurs réelles des variables de liaison et utilisera des statistiques de données pour réévaluer et éventuellement régénérer le plan d'exécution de la requête. Je doute que jeter un œil aura un effet sur la construction qui est discutée, car elle ne dépend pas des statistiques de données.
mustaccio