Это случай, произошедший в прошлом году в системе одного клиента: иногда обычный запрос к крошечной таблице, казалось, «зависал», и его приходилось убивать и запускать заново. В чём же дело?
Рассматриваемая таблица содержала всего несколько миллионов строк данных с максимальным размером строки 60 байт, и запрос обычно выполнялся за несколько секунд, но иногда он «зависал» и либо его приходилось убивать, либо он выполнялся десятки минут. Диагностические средства, запущенные во время возникновения проблемы, не показывали каких-либо необычных ожиданий, давления на сервер не было, а план запроса, генерируемый при долгом выполнении, был практически таким же.
Единственное, что было заметно, — когда проблема возникала, в рамках компиляции запроса происходило обновление статистики столбца, но как такая крошечная таблица могла быть первопричиной проблемы? Расчётное дисковое пространство для размера строк и их количества составляло около 250 МБ, но при частоте дискретизации статистики всего 4% расширенные события показали событие auto_stats, выполнявшееся почти час!
Дальнейшее расследование показало, что, хотя таблица содержала всего несколько сотен мегабайт данных, она занимала более 25 ГБ дискового пространства! Мы с Джонатаном были озадачены тем, как такое могло быть. Верно, в более ранних версиях SQL Server были ошибки, например, с типами данных LOB, когда использовалась только одна страница из каждого выделенного экстента (из 8 страниц), но ни одной такой ошибки в настоящее время не было известно, и даже что-то подобное не могло бы объяснить, почему таблица занимает более чем в 100 раз больше дискового пространства, чем данные в таблице.
Что ещё любопытно, всё пространство находилось в некластерном индексе. Как такое вообще возможно?
Я предложил посмотреть, какие страницы распределены для таблицы. Бинго! 25 ГБ страниц IAM (битовые карты распределения, по одной на каждые 4 ГБ) были распределены для этого единственного некластерного индекса.
Дальнейшее расследование показало, что некластерный индекс имел тысячи секций, каждая с горсткой страниц индекса и около 1500 страниц IAM. Ведущим ключом некластерного индекса был столбец ROWVERSION, а интенсивность изменений в таблице была очень высокой, поэтому по сути схема и шаблон использования создавали длинную цепочку IAM для каждой секции, практически без данных.
Проще говоря, это означало, что для обновления статистики по столбцу, охваченному некластерным индексом, потребовалось бы прочитать и обработать 25 ГБ страниц IAM в поисках выделенных экстентов, чтобы затем обработать записи индекса и создать статистику.
Решение? Самым быстрым первым исправлением было удалить и воссоздать некластерный индекс, чтобы избавиться от длинных цепочек IAM (вместо того чтобы перестраивать индекс, что потребовало бы выполнения той же трудоёмкой задачи чтения всех страниц IAM!), а затем внедрить регулярное обслуживание индексов, чтобы в первую очередь предотвратить удлинение цепочек IAM.

Комментариев нет:
Отправить комментарий