"где (ParamID = @ParamID) OR (@ParamID = -1)" хорошая практика в SQL-выборке

Я использовал для написания SQL-статусов, таких как

select * from teacher where (TeacherID = @TeacherID) OR (@TeacherID = -1)

читать дальше

и передать значение @TeacherID = -1, чтобы выбрать всех преподавателей.

теперь я беспокоюсь о производительности можете ли вы сказать мне, что это хорошая практика или плохая?

большое спасибо

Ответ 1

Если TeacherID индексируется, и вы передаете значение, отличное от -1, как TeacherID для поиска сведений о конкретном преподавателе, тогда этот запрос закончит выполнение полного сканирования таблицы, а не потенциально гораздо более эффективного возможность поиска в индексе для получения деталей конкретного учителя...

... Если вы не используете SQL Server 2008 SP1 CU5 и более поздние версии и используйте подсказку OPTION (RECOMPILE). См. Динамические условия поиска в T-SQL для окончательной статьи по этой теме.

Ответ 2

Мы используем это очень ограниченно в хранимых процедурах.

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

Однако для небольших наборов данных (я бы сказал, менее 1000 записей, но это предположение) должно быть хорошо. Вы должны будете протестировать в своей конкретной среде.

Если это в хранимой процедуре, вы можете включить что-то вроде опции WITH RECOMPILE, чтобы план восстанавливался при каждом выполнении. Это добавляет (немного) к времени для каждого запуска, но в течение нескольких прогонов может фактически сократить среднее время выполнения. Кроме того, это позволяет базе данных проверять фактический запрос и "короткое замыкание" части, которые не нужны для каждого вызова.

Если вы напрямую создаете свой SQL и передаете его, я бы предложил вам сделать часть, которая строит ваш sql немного умнее, чтобы она включала только часть предложения where, которое вам действительно нужно.


Другой путь, который вы можете рассмотреть, - это использовать запросы UNION ALL в отличие от необязательных параметров. Например:

SELECT * FROM Teacher WHERE (TeacherId = @TeacherID)
UNION ALL
SELECT * FROM Teacher WHERE (@TeacherId = -1)

Это фактически выполняет то же самое; Тем не менее, план запроса может быть кэшируемым. Мы также использовали этот метод в нескольких местах и ​​увидели улучшение производительности при использовании WITH RECOMPILE. Мы не делаем этого повсюду, потому что некоторые из наших запросов чрезвычайно сложны, и я предпочел бы поразить производительность, чем усложнять их.

В конечном счете, вам нужно провести много испытаний.


Здесь есть вторая часть, которую вы должны пересмотреть. SELECT *. ВСЕГДА предпочтительнее называть столбцы, которые вы хотите вернуть, и убедиться, что вы возвращаете только те, которые вам действительно понадобятся. Перемещение данных по границам сети очень дорогое, и вы обычно можете получить достаточный прирост производительности, просто указав именно то, что хотите. Кроме того, если вам очень нужно, вы можете иногда покрывать индексы, чтобы механизм базы данных даже не должен касаться базовых таблиц, чтобы получить нужные вам данные.

Ответ 3

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

If @TeacherID = -1
   exec proc_Get_All_Teachers
else
   exec proc_Get_Teacher_By_TeacherID @TeacherID

Каждый из них может быть оптимизирован индивидуально.

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

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