Skip to content

Как думать подобно SQL Server: если статистика не помогает

Пересказ статьи Brent Ozar. How to Think Like the SQL Server Engine: When Statistics Don’t Help



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

SELECT LastAccessDate, Id, DisplayName, Age
FROM dbo.Users
WHERE LastAccessDate BETWEEN '2018-08-27' AND '2018-08-28'
ORDER BY LastAccessDate;

SELECT LastAccessDate, Id, DisplayName, Age
FROM dbo.Users
WHERE CAST(LastAccessDate AS DATE) = '2018-08-27'
ORDER BY LastAccessDate;

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


Хорошая новость состоит в том, что оба плана выполняют index seek + key lookup. Constant Scan в нижнем плане - это SQL Server выясняет, какой должна быть первая дата, если он должен искать конкретную дату/время, чтобы начать процесс преобразования типа (CAST). Если вы постоянно читаете блог, то, вероятно, прочитали и то, где говорится о том, что, если вы используете функции в предложении WHERE, SQL Server не будет использовать индекс, или что он не будет выполнять поиск по индексу. Это не вполне верно, что показывает нижний план запроса - и это круто! В подобные моменты я люблю SQL Server.

Плохая новость - это то, что они имеют сильно различающиеся оценки числа строк. Верхний оценивает число отвечающей этой дате строк как 1989, что видно из “2443 of 1989” на верхнем Index Seek.

Нижний имеет другую оценку числа строк: 1.

SQL Server вернул 2443 строк вместо ожидаемой одной.


И, если вы наведете мышку на index seek, чтобы посмотреть детали, то увидите, что SQL Server хорошо знал, какую дату он искал - и даже что наш CAST преобразовывал.


Но статистика не помогла. SQL Server просто не захотел угадывать, сколько строк будет соответствовать дате 2018-08-27.

В этом случае оценка 1 для числа строк сильно помогла мне, потому что это подтолкнуло SQL Server к снижению оценки числа строк и, как следствие, заставило использовать index seek + key lookup. Но...что если это была плохая идея?

Давайте проверим другую дату.


Теперь давайте возьмем дату на 3 дня позже:

SELECT LastAccessDate, Id, DisplayName, Age
FROM dbo.Users
WHERE LastAccessDate BETWEEN '2018-08-31' AND '2018-09-01'
ORDER BY LastAccessDate;

SELECT LastAccessDate, Id, DisplayName, Age
FROM dbo.Users
WHERE CAST(LastAccessDate AS DATE) = '2018-08-31'
ORDER BY LastAccessDate;

Так случилось, что 24380 человек авторизовались в этот день, поэтому теперь верхний план выполнения сильно отличается от нижнего:


В этом случае низкая оценка в 1 строку обернулась против меня. Верхний запрос понял, что должно вернуться свыше 24000 строк, поэтому он делает сканирование кластеризованного индекса. Нижний с оценкой 1 строка вызывает index seek + key lookup, а, как вы помните из наших прежних уроков, index seek + key lookup значительно менее эффективны, т.к. вы добавили больше строк, что показывает статистика ввода/вывода:


Верхний запрос делал 7405 чтений (таблица целиком), в то время как нижний ПОЧТИ В ДЕСЯТЬ РАЗ БОЛЬШЕ.

Чем легче SQL Server'у прочитать ваш запрос и быстро догадаться, сколько строк должно вернуться, тем более быстрый план он обычно строит. Чем больше вы темните - даже мельчайшая обфускация, которая совершенно очевидна для вас - тем менее вероятно, что вы получите быстрый план запроса.

Или, вы собираетесь компенсировать это, поработав над индексами. И мы сделаем это в следующей публикации.

Обратные ссылки

Нет обратных ссылок

Комментарии

Показывать комментарии Как список | Древовидной структурой

Нет комментариев.

Автор не разрешил комментировать эту запись

Добавить комментарий

Enclosing asterisks marks text as bold (*word*), underscore are made via _word_.
Standard emoticons like :-) and ;-) are converted to images.

To prevent automated Bots from commentspamming, please enter the string you see in the image below in the appropriate input box. Your comment will only be submitted if the strings match. Please ensure that your browser supports and accepts cookies, or your comment cannot be verified correctly.
CAPTCHA

Form options

Добавленные комментарии должны будут пройти модерацию прежде, чем будут показаны.