MySQL Short Circuit IF () функционирует? - PullRequest
5 голосов
/ 15 сентября 2010

Мне нужно запрашивать данные из второй таблицы, но только если встречается редкий набор условий в первичной таблице:

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

a, b и c условия почти всегда ложны, поэтомуя думаю, что подзапрос никогда не будет выполняться для большинства строк в наборе результатов и, следовательно, будет быстрее, чем соединение.Но это верно только в том случае, если оператор IF () замкнут.

Есть ли это?

Спасибо за любую помощь, которую вы, ребята, можете предоставить.

Ответы [ 4 ]

8 голосов
/ 21 сентября 2010

Ответ ДА.
IF (cond, expr_true, expr_false) в запросе mysql закорочен.

Вот тест, использующий @variables для доказательства факта:

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

Результат - 5 из всех трех запросов SELECT.

Если бы функция IF () НЕ была замкнута, результатом было бы '5' из SELECT # 1, '6' из SELECT # 2 и '7' из последнего "select @var".

Это связано с тем, что выражение 'true' НИКОГДА не выполняется, в select # 1 и ложное выражение не выполняется для select # 2.

Обратите внимание, что оператор ': =' используется для изменения @var в запросе SQL (предложения select, from и where). Из этого вы можете получить действительно причудливый / сложный SQL. Я использовал @vars для применения «процедурной» логики в запросе SQL.

- Дж. Йоргенсон -

2 голосов
/ 22 сентября 2010

С помощью Дж. Йоргенсона я придумал собственный тестовый пример. Его пример не пытается замкнуть накоротко при оценке состояния, но, используя его идею, я придумал свой собственный тест и убедился, что MySQL действительно замыкает проверку условия 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

Во втором примере MySQL правильно закорочен: @var никогда не устанавливается на 10.

Спасибо за помощь Дж. Йоргенсон!

0 голосов
/ 25 июля 2014

Это зависит.

ЕСЛИ не закорачивает, так что его можно использовать, чтобы избежать предупреждений об усечении с помощью GROUP_CONCAT, например, в:

set @@group_concat_max_len = 5;

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

результат будет «фактическим результатом», но вы получите предупреждение:

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

- то же самое предупреждение, которое вы получаете с менее тривиальными выражениями GROUP_CONCAT, такими как отдельные ключи, и вообще без IF.

0 голосов
/ 15 сентября 2010

Попробуйте в анализаторе SQL.Если вы хотите быть в безопасности и не должны доверять базе данных, чтобы она работала в одном направлении (и никогда не меняла это поведение в новых версиях), просто сделайте два запроса и выполните IF программно.

...