Статистика может устаревать.
Когда происходит массовая вставка данных, при загрузках, массовом вводе документов. Статистику нужно регулярно обновлять. Это может происходить несколькими способами:
- Вручную, когда выполняем команду UPDATE STATISTICS. Может быть как FULLSCAN, так и SAMPLE (частично)
- Второй вариант – делаем перестроение индекса (REBUILD). Вместе с этим соответствующая статистика помечается как устаревшая, и затем обновляется.
- Чтобы сделать жизнь проще, в MS SQL добавили настройку под названием AUTO_UPDATE_STATISTICS. А чтобы жизнь стала совсем сладкой, также добавили параметр AUTO_UPDATE_STATISTICS_ASYNC, т.е обновление статистики асинхронно. SQL Server отслеживает количество изменений строк (вставок, удалений, обновлений) с момента последнего обновления статистики и сравнивает его с порогом. Когда порог превышен, статистика помечается как устаревшая. Далее запускается процесс асинхронного пересчета статистики.
На практике это выглядит так: запустили запрос - система увидела, что статистика устарела, запустила процесс обновления статистики по таблице, при этом запрос продолжает выполняться.
И как раз тут мы попадаем в ловушку ожидания на таком типе блокировки как LCK_M_SCH_M / LCK_M_SCH_S, связанные с попыткой получить блокировки модификации схемы Sch-M / Sch-S.
LCK_M_SCH_M - Будет возникать у служебной сессии ms sql, которая запустила пересчет статистики. Запрос компилируется и выполняется с существующей, возможно устаревшей статистикой, а обновление статистики уходит в фоновую сессию. Эта сессия будет пересчитывать статистику, и затем обновлять сам объект статистики, чтобы другие запросы могли пользоваться обновленной статистикой. Но, блокировка на этот объект статистики будет держаться до тех пор, пока не закончится выполняться наш основной запрос (тот самый неоптимальный и долгий). И только после того как долгий и неоптимальный запрос выполнится, объект статистики подменится на новый, и блокировка будет снята.
Только вот есть еще один ключевой нюанс, пока выполнение долгого запроса не завершится, статистика обновлена быть не может. И все другие сессии, которые заходят воспользоваться этим объектом статистики, буду ждать в очереди с типом ожидания LCK_M_SCH_S. Они как бы хотят прочитать, что там в этой статистике, а сервер им говорит подождите в данный момент статистика обновляется. Таким образом может скопиться очень длинный паровоз из других сессий, которые ожидают возможности прочитать эту статистику.
Весьма непрозрачная история. Отчет, который выполняется без транзакции с NOLOCK, все равно может вызвать ожидания. Этот сценарий характерен именно для включенного AUTO_UPDATE_STATISTICS_ASYNC. При синхронном обновлении статистики проблема проявляется иначе: запрос ждёт обновления статистики перед компиляцией и выполнением, компиляция запроса не начнется, пока не завершится обновление статистики. Только после этого запустится компиляция запроса.
А вы ловили такие ожидания у себя в практике ?
Когда происходит массовая вставка данных, при загрузках, массовом вводе документов. Статистику нужно регулярно обновлять. Это может происходить несколькими способами:
- Вручную, когда выполняем команду UPDATE STATISTICS. Может быть как FULLSCAN, так и SAMPLE (частично)
- Второй вариант – делаем перестроение индекса (REBUILD). Вместе с этим соответствующая статистика помечается как устаревшая, и затем обновляется.
- Чтобы сделать жизнь проще, в MS SQL добавили настройку под названием AUTO_UPDATE_STATISTICS. А чтобы жизнь стала совсем сладкой, также добавили параметр AUTO_UPDATE_STATISTICS_ASYNC, т.е обновление статистики асинхронно. SQL Server отслеживает количество изменений строк (вставок, удалений, обновлений) с момента последнего обновления статистики и сравнивает его с порогом. Когда порог превышен, статистика помечается как устаревшая. Далее запускается процесс асинхронного пересчета статистики.
На практике это выглядит так: запустили запрос - система увидела, что статистика устарела, запустила процесс обновления статистики по таблице, при этом запрос продолжает выполняться.
И как раз тут мы попадаем в ловушку ожидания на таком типе блокировки как LCK_M_SCH_M / LCK_M_SCH_S, связанные с попыткой получить блокировки модификации схемы Sch-M / Sch-S.
LCK_M_SCH_M - Будет возникать у служебной сессии ms sql, которая запустила пересчет статистики. Запрос компилируется и выполняется с существующей, возможно устаревшей статистикой, а обновление статистики уходит в фоновую сессию. Эта сессия будет пересчитывать статистику, и затем обновлять сам объект статистики, чтобы другие запросы могли пользоваться обновленной статистикой. Но, блокировка на этот объект статистики будет держаться до тех пор, пока не закончится выполняться наш основной запрос (тот самый неоптимальный и долгий). И только после того как долгий и неоптимальный запрос выполнится, объект статистики подменится на новый, и блокировка будет снята.
Только вот есть еще один ключевой нюанс, пока выполнение долгого запроса не завершится, статистика обновлена быть не может. И все другие сессии, которые заходят воспользоваться этим объектом статистики, буду ждать в очереди с типом ожидания LCK_M_SCH_S. Они как бы хотят прочитать, что там в этой статистике, а сервер им говорит подождите в данный момент статистика обновляется. Таким образом может скопиться очень длинный паровоз из других сессий, которые ожидают возможности прочитать эту статистику.
Весьма непрозрачная история. Отчет, который выполняется без транзакции с NOLOCK, все равно может вызвать ожидания. Этот сценарий характерен именно для включенного AUTO_UPDATE_STATISTICS_ASYNC. При синхронном обновлении статистики проблема проявляется иначе: запрос ждёт обновления статистики перед компиляцией и выполнением, компиляция запроса не начнется, пока не завершится обновление статистики. Только после этого запустится компиляция запроса.
А вы ловили такие ожидания у себя в практике ?