SQL Server - короткое замыкание запроса? - PullRequest
4 голосов
/ 19 декабря 2008

Поддерживают ли запросы T-SQL в SQL Server короткое замыкание?

Например, у меня есть ситуация, когда у меня есть две базы данных, и я сравниваю данные между двумя таблицами, чтобы сопоставить и скопировать некоторую информацию. В одной таблице поле «ID» всегда будет иметь начальные нули (например, «000000001234»), а в другой таблице поле ID может иметь или не иметь начальные нули (может быть «000000001234» или «1234»).

Так что мой запрос на совпадение выглядит примерно так: выберите * из таблицы1, где table1.ID LIKE '% 1234'

Чтобы ускорить процесс, я думаю о добавлении ИЛИ до того, как это просто говорит: table1.ID = table2.ID для обработки случая, когда оба идентификатора имеют дополняющие нули и равны.

Будет ли это ускорять запрос, сопоставляя элементы в «=» и не оценивая значение LIKE для каждой отдельной строки (это приведет к короткому замыканию и пропуску LIKE)?

Ответы [ 7 ]

7 голосов
/ 19 декабря 2008

SQL Server делает НЕ короткое замыкание, когда условия. это невозможно, поскольку это система, основанная на затратах: Как SQL Server закорачивает ГДЕ оценка состояния .

7 голосов
/ 19 декабря 2008

Вы можете добавить вычисляемый столбец в таблицу. Затем индексируйте вычисляемый столбец и используйте этот столбец в соединении.

Ex:

Alter Table Table1 Add PaddedId As Right('000000000000' + Id, 12)
Create Index idx_WhateverIndexNameYouWant On Table1(PaddedId)

Тогда ваш запрос будет ...

select * from table1 where table1.PaddedID ='000000001234'

Это будет использовать индекс, который вы только что создали, чтобы быстро вернуть строку.

3 голосов
/ 27 апреля 2010

На всякий случай это полезно, как объясняет связанная страница в ответе Младена Прайдика, предложения CASE оцениваются на предмет короткого замыкания.

3 голосов
/ 19 декабря 2008

Как насчет

table1WithZero.ID = REPLICATE('0', 12-len(table2.ID))+table2.ID

В этом случае он должен иметь возможность использовать индекс по таблице1

3 голосов
/ 19 декабря 2008

Вы хотите убедиться, что хотя бы одна из таблиц использует свой фактический тип данных для идентификаторов и что она может использовать поиск по индексу, если это возможно. Это зависит от избирательности вашего запроса и частоты совпадений, чтобы определить, какой из них следует преобразовать в другой. Если вы знаете, что вам нужно сканировать всю первую таблицу, то вы все равно не сможете использовать поиск, и вам следует преобразовать этот идентификатор в тип данных другой таблицы.

Чтобы убедиться, что вы можете использовать индексы, также избегайте 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, хотя (другими словами, ЛЕВОЕ ВНЕШНЕЕ СОЕДИНЕНИЕ к T2), то вам может быть лучше:

WHERE
     CAST(T1.ID AS INT) = T2.ID

Составьте несколько планов запросов для каждого метода, если вы не уверены, и посмотрите, что работает лучше.

Абсолютно лучший путь - это то, что предложили другие, и измените тип данных таблиц, чтобы он соответствовал, если это вообще возможно. Даже если вы не можете сделать это до завершения этого проекта, включите его в свой список дел на ближайшее будущее.

1 голос
/ 19 декабря 2008

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

1 голос
/ 19 декабря 2008

исправить базу данных, чтобы она была согласованной

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 для CAST для целого числа будет лучше, если это возможно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...