Поддерживают ли запросы T-SQL в SQL Server короткое замыкание?
Например, у меня есть ситуация, когда у меня есть две базы данных, и я сравниваю данные между двумя таблицами, чтобы сопоставить и скопировать некоторую информацию. В одной таблице поле «ID» всегда будет иметь ведущие нули (например, «000000001234»), а в другой таблице поле идентификатора может иметь или не иметь начальные нули (может быть «000000001234» или «1234»).
Итак, мой запрос на сопоставление этих двух выглядит примерно так: выберите * from table1, где table1.ID LIKE '% 1234'
Чтобы ускорить процесс, я подумываю добавить ИЛИ до того, как будет сказано: table1.ID = table2.ID для обработки случая, когда оба идентификатора имеют заполненные нулями и равны.
Ускоряет ли это запрос, сопоставляя элементы в «=» и не оценивая LIKE для каждой отдельной строки (произойдет ли короткое замыкание и пропустить LIKE)?
Что ж, фильтр поиска будет больше похож на "% 00001234" - все еще есть некоторые ведущие нули.


исправить базу данных, чтобы она была согласованной
select * from table1 where table1.ID LIKE '%1234'
будет соответствовать '1234', '01234', '00000000001234', но также и '999991234'. Использование LIKE в значительной степени гарантирует сканирование индекса (при условии, что table1.ID проиндексирован!). Очистка данных значительно повысит производительность.
если очистка данных невозможна, напишите пользовательскую функцию (UDF) для удаления начальных нулей, например
select * from table1 where dbo.udfStripLeadingZeros(table1.ID) = '1234'
это может не улучшить производительность (так как функцию придется запускать для каждой строки), но это устранит ложные совпадения и сделает цель запроса более очевидной.
Обновлено: предложение Тома H о преобразовании в целое число было бы лучше всего, если это возможно.
вроде не гарантирует сканирование таблицы, как "% 1234" - это сканирование таблицы. например, «1234%» - это не сканирование таблицы, при условии, что столбец проиндексирован, он будет использовать индекс для поиска 1234 ...
@ Джош: я сказал «сканирование индекса», а не «сканирование таблицы».
@ Стивен: да, я не понимаю, почему, но когда я прочитал это в первый раз, я мог бы поклясться, что там сказано: таблица ... Я старею, я думаю ;-)
Но в любом случае я думаю, что префикс с помощью символа подстановки приведет к сканированию таблицы, возможно, поэтому я их запутал.
Если идентификатор является чисто числовым (как ваш пример), я бы рекомендовал (если возможно) заменить это поле на числовой тип. Если база данных уже используется, изменить тип может быть сложно.
Да, я не могу изменить исходную таблицу.
Вы хотите убедиться, что хотя бы одна из таблиц использует свой фактический тип данных для идентификаторов и что она может использовать поиск по индексу, если это возможно. Это зависит от избирательности вашего запроса и количества совпадений, чтобы определить, какой из них следует преобразовать в другой. Если вы знаете, что вам нужно просмотреть всю первую таблицу, вы все равно не можете использовать поиск и вам следует преобразовать этот идентификатор в тип данных другой таблицы.
Чтобы убедиться, что вы можете использовать индексы, также избегайте LIKE. Например, гораздо лучше иметь:
WHERE
T1.ID = CAST(T2.ID AS VARCHAR) OR
T1.ID = RIGHT('0000000000' + CAST(T2.ID AS VARCHAR), 10)
чем:
WHERE
T1.ID LIKE '%' + CAST(T2.ID AS VARCHAR)
Как заметил Стивен А. Лоу, второй запрос тоже может быть неточным.
Если вы собираетесь использовать все строки из T1 (другими словами, LEFT OUTER JOIN to T2), вам может быть лучше:
WHERE
CAST(T1.ID AS INT) = T2.ID
Если вы не уверены, составьте несколько планов запросов для каждого метода и посмотрите, какой из них работает лучше всего.
Абсолютно лучший путь, как предлагали другие, - изменить тип данных таблиц, чтобы он соответствовал, если это вообще возможно. Даже если вы не можете сделать это до истечения срока реализации этого проекта, внесите его в свой список дел на ближайшее время.
Вы можете добавить в таблицу вычисляемый столбец. Затем проиндексируйте вычисляемый столбец и используйте этот столбец в соединении.
Бывший:
Alter Table Table1 Add PaddedId As Right('000000000000' + Id, 12)
Create Index idx_WhateverIndexNameYouWant On Table1(PaddedId)
Тогда ваш запрос будет ...
select * from table1 where table1.PaddedID ='000000001234'
Это будет использовать только что созданный индекс для быстрого возврата строки.
Хорошо. Никаких OR, UDF в строке, индексируемых и т. д.
Просто имейте в виду, что это вызовет (надеюсь, незначительное) попадание в вставки и обновления. Хорошая идея, если это не проблема.
если вы не можете исправить данные, чтобы они были согласованными, это следующее лучшее решение
Как насчет,
table1WithZero.ID = REPLICATE('0', 12-len(table2.ID))+table2.ID
В этом случае он должен иметь возможность использовать индекс в таблице1
SQL Server выполняет короткое замыкание НЕТ, если условия. это невозможно, поскольку это система, основанная на затратах: Как SQL Server закорачивает оценку условия WHERE.
На всякий случай это полезно, как объясняет связанная страница в ответе Младена Прайдича, при оценке короткого замыкания находятся в разделе CASE.
Как насчет table1.ID LIKE "% 1234" будет соответствовать "31234"?