2010-09-14 25 views
5

J'ai besoin d'interroger des données à partir d'une seconde table, mais seulement si est remplie d'un ensemble rare de conditions dans le tableau principal:Est-ce que MySQL court-circuite la fonction IF()?

SELECT ..., IF(a AND b AND c AND (SELECT 1 FROM tableb ...)) FROM tablea ... 

a, b, et les conditions de c sont presque toujours faux, si ma pensée est la sous-requête ne s'exécutera jamais pour la plupart des lignes du jeu de résultats et sera donc bien plus rapide qu'une jointure. Mais cela ne serait vrai que si l'instruction IF() court-circuite.

Est-ce que c'est?

Merci pour toute aide que vous pouvez fournir.

Répondre

2

Avec l'aide de J. Jorgenson je suis venu avec mon propre cas de test. Son exemple n'essaie pas de court-circuiter dans l'évaluation de la condition, mais en utilisant son idée, j'ai inventé mon propre test et vérifié que MySQL court effectivement le contrôle de condition IF().

SET @var:=5; 
SELECT IF(1 = 0 AND (@var:=10), 123, @var); #Expected output: 5 
SELECT IF(1 = 1 AND (@var:=10), @var, 123); #Expected output: 10 

Sur le second exemple, MySQL est correctement court-circuit: @var ne se prépare à 10.

Merci pour l'aide J. Jorgenson!

0

Essayez-le dans l'analyseur SQL. Si vous voulez être prudent et ne pas avoir à faire confiance à la base de données pour fonctionner d'une certaine façon (et ne pas changer ce comportement dans les nouvelles versions), faites juste deux requêtes et faites le IF par programmation.

8

La réponse est OUI.
L'IF (cond, expr_true, expr_false) dans une requête mysql est court-circuité.

Voici un test, en utilisant @variables pour prouver le fait:

SET @var:=5; 
SELECT IF(1 = 0, (@var:[email protected] + 1), @var); -- using ':=' operator to modify 'true' expr @var 
SELECT IF(1 = 1, @var, (@var:[email protected] + 1)); -- using ':=' operator to modify 'false' expr @var 
SELECT @var; 

Le résultat est '5' de trois requêtes SELECT. Si la fonction IF() n'était PAS court-circuitée, le résultat serait un '5' de SELECT # 1, et '6' de SELECT # 2, et un '7' du dernier "select @var". Ceci est dû au fait que l'expression 'true' est JAMAIS exécutée, dans select # 1 et que l'expression false n'est pas non plus exécutée pour select # 2.

Notez que l'opérateur ': =' est utilisé pour modifier un @var, dans une requête SQL (clauses select, from, et where). Vous pouvez obtenir un SQL vraiment fantaisie/complexe à partir de cela. J'ai utilisé @vars pour appliquer une logique "procédurale" dans une requête SQL.

- J Jorgenson -

0

Cela dépend.

IF ne pas court-circuit tel qu'il peut être utilisé pour éviter les avertissements de troncature avec GROUP_CONCAT, par exemple dans:

set @@group_concat_max_len = 5; 

select if(true or @var:=group_concat('warns if evaluated'), 'actual result', @var); 

le résultat sera « résultat réel », mais vous aurez un avertissement :

Warning (Code 1260): Row 1 was cut by GROUP_CONCAT() 

qui est le même avertissement que vous obtenez avec moins triviales expressions GROUP_CONCAT, tels que les clés distinctes, et sans le cas échéant.