Журнал Начинающего ВебМастера 33, 2010-11-24 15:36
Здравствуйте,
Оптимизация
или удобство SQL
Сегодня оптимизировал запрос, который до моего вмешательства работал 4
часа. Проблема была в том, что в нем не правильно использовалась
функция isnull. Это очень удобная функция, особенно, если использовать
ее в блоке SELECT, но ее нужно аккуратно использовать в блоке WHERE.
Я оптимизировал функцию, которая получала в качестве параметра
необходимый тип данных. Если переменная равна NULL, то функция должна
вернуть все данные.
Чтобы проще было следить за тем, что я говорю, давайте представим себе
следующий запрос: declare @city varchar(100); set @city = null; select FirstName, LastName, City from Members where isnull(@city, City) = City
Я упростил функцию для простого запроса, чтобы проще было разбирать
его. Если переменная @city равна null, то isnul(@city, City) вернет
значение City для текущей строки и оно конечно же будет равно City, а
значит запрос вернет содержимое всей базы. Если City установлен в
какой-то город, то запрос вернет только этот город. Красиво? Да, но
очень медленно.
Как показал мой пример, функция isnul не дает SQL серверу эффективно
использовать индексы в этом месте. Сервер практически скаровал таблицу,
а у меня были не люди в таблицы, а транзакции. Моя таблица транзакций
состоит из миллиардов записей со сложными связями на другие таблицы, в
том числе и на себя и запрос Server уходил в серьезные 4-х часовые
раздумия. Никакие индексы не помогали.
Не используйте такую конструкцию на больших таблицах. Лучше написать: declare @city varchar(100); set @city = null; select FirstName, LastName, City from Members where (@city = City or @city is
null)
Если City не равен null, то будет так же возвращен только этот город,
иначе вся таблица. Но такое банальное изменение позволило запросу,
который я оптимизировал, выполняться меньше 30 минут. Подобные приколы
как isnull(@city, City) = City удобны и будут работать быстро в секции
SELECT, но не в WHERE. По крайней мере по моим наблюдениям.