25.11.24

Sequential Read Ahead

Автор: Craig Freedman Sequential Read Ahead

Балансировка загрузки процессоров и ввода-вывода очень важна для обеспечения лучшей производительности и оптимизации обслуживания нагрузки сервера. В SQL Server реализованы два механизма асинхронного ввода-вывода: последовательное упреждающее чтение (sequential read ahead) и случайная упреждающая выборка (random prefetching). Оба они предназначены для балансировки нагрузки в многопроцессорных системах.

Чтобы понять, почему асинхронный ввод-вывод так важен, рассмотрим разницу между пропускной способности конвейеров процессорных ядер и подсистемы ввода-вывода. Контроллер памяти для современного процессора может обеспечить последовательную передачу данных со скоростью больше 5 Гбайт в секунду из расчёта на сокете, а случайные ячейки памяти (в зависимости от того, как вы это будете измерять) может извлекать со скоростью выше 50 миллионов обращений в секунду. Для сравнения, жесткий диск SAS 15K класса предприятия может считывать чуть быстрее 125 Мбайт в секунду последовательно или порядка 200 случайных операций ввода-вывода в секунду (IOPS). Твердотельные диски (SSD) могут сократить разницу между производительностью последовательного и случайного ввода-вывода, исключив из уравнения механическое вращение шпинделя, но «пропасть» в производительности между процессором и дисками останется. Чтобы сократить этот разрыв, в серверы нередко устанавливают по 10 и более дисков из расчёта на каждый сокет. Также важно учитывать и балансировать всю подсистему ввода-вывода, включая количество и тип дисковых контроллеров, а не только сами диски, но это не является темой данной статьи.

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

Когда SQL Server выполняет последовательный просмотр большой таблицы, механизм хранения инициирует упреждающее чтение, которое призвано заранее загрузить страницы в память и подготовить к просмотру до того, как они понадобятся процессору запросов. Механизм упреждающего чтения пытается опережать на 500 страниц нужды просмотра. Мы можем увидеть это в действии, проверив вывод с установкой SET STATISTICS IO ON. Например, я выполнил показанный ниже запрос к базе данных TPC-H с коэффициентом масштабирования 1ГБ. Таблица LINEITEM содержит примерно 6 миллионов строк.

SET STATISTICS IO ON

SELECT COUNT(*) FROM LINEITEM

Table 'LINEITEM'. Scan count 3, logical reads 22328, physical reads 3, read-ahead reads 20331, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

Повторное исполнение запроса показывает, что таблица теперь закэширована в буферном пуле:

SELECT COUNT(*) FROM LINEITEM

Table 'LINEITEM'. Scan count 3, logical reads 22328, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

При анализе производительности последовательного ввода-вывода важно различать просмотр в порядке размещения страниц (в порядке распределения) и просмотр в порядке сортировки индекса. Просмотр в порядке распределения пытается прочитать страницы в том порядке, в котором они физически хранятся на диске, в то время как просмотр в порядке индекса считывает страницы в том порядке, в котором отсортированы данные на страницах индекса.

Обратите внимание, что между логическими томами, которые видит SQL Server, и физическими дисками во многих случаях существует несколько уровней абстракции, таких как RAID массивы или SAN. Таким образом, даже просмотр в порядке распределения может оказаться не оптимально упорядоченным.

Зачастую SQL Server пытается сортировать и читать страницы в порядке распределения даже для просмотра в порядке индекса, поскольку просмотр в порядке распределения, как правило, будет быстрее, поскольку страницы считываются в том порядке, в котором они записаны на диск, что минимизирует число операций поиска на диске. Кучи не имеют внутреннего порядка и, таким образом, для них всегда используется просмотр в порядке распределения. Для индексов просмотр в порядке распределения используется только если уровень изоляции Read Uncommitted (или используется подсказка NOLOCK) и только если процесс запроса не запрашивает упорядоченный просмотр. Дефрагментация индексов помогает обеспечить близкую производительность просмотра с упорядочением по индексу и с упорядочением по распределению.

Комментариев нет:

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