Мой вопрос заключается в том, как SQL Server обрабатывает запрос, который должен вытянуть больший объем данных в буферный кеш, чем есть доступное пространство? Этот запрос будет содержать несколько объединений, поэтому результирующий набор не существует в этом формате уже на диске, и ему потребуется скомпилировать результаты. Но даже после компиляции все равно требуется больше места, чем доступно в буферном кеше.
Я приведу пример. Предположим, у вас есть экземпляр SQL Server, который имеет 6 ГБ свободного пространства в буфере кэша. Я запускаю запрос с несколькими объединениями, который считывает 7 ГБ данных. Как SQL Server может ответить на этот запрос? Временно ли он хранит данные в базе данных tempdb? Это терпит неудачу? Делает ли он что-то, что просто читает данные с диска и компилирует сегменты одновременно?
Кроме того, что произойдет, если я попытаюсь вернуть 7 ГБ общих данных, это изменит то, как SQL Server обрабатывает это?
Мне уже известно о нескольких способах решения этой проблемы, мне просто любопытно, как SQL Server внутренне обрабатывает этот запрос, когда он выполняется, как указано.
Кроме того, я уверен, что эта информация где-то существует, но мне не удалось ее найти.
Ответы:
Страницы считываются в память по мере необходимости. Если свободной памяти нет, самая старая неизмененная страница заменяется входящей страницей.
Это означает, что если вы выполняете запрос, который требует больше данных, чем может поместиться в памяти, многие страницы будут жить в памяти очень недолго, что приведет к большому количеству операций ввода-вывода.
Вы можете увидеть этот эффект, посмотрев на счетчик «Продолжительность жизни страницы» в системном мониторе Windows. Посмотрите на https://sqlperformance.com/2014/10/sql-performance/knee-jerk-page-life-expectancy некоторые подробности об этом счетчике.
В комментариях вы конкретно спросили, что происходит, когда результаты запроса превышают доступное пространство буфера. Возьмите простейший пример
select * from some_very_big_table;
- предположим, что таблица имеетmax server memory (MB)
размер 32 ГБ и настроена на 24 ГБ. Все 32 ГБ табличных данных будут считываться на страницы в буфере страниц по одной защелкой, отформатированные в сетевые пакеты и отправленные по сети. Это происходит постранично; Вы могли бы одновременно выполнить 300 таких запросов, и при условии, что блокирования не было, данные для каждого запроса будут считываться в буферное пространство страницы, страницу за раз, и выводиться на связь так быстро, как может клиент запрашивать и потреблять данные. Как только все данные с каждой страницы были отправлены на провод, страница становится незапертой и очень быстро заменяется какой-либо другой страницей с диска.В случае более сложного запроса, скажем, например, агрегирования результатов из нескольких таблиц, страницы будут загружаться в память точно так же, как указано выше, как того требует процессор запросов. Если обработчику запросов требуется временное рабочее пространство для вычисления результатов, он будет знать об этом заранее, когда будет составлять план для запроса, и запросит рабочее пространство (память) из SQLOS . SQLOS в какой-то момент (при условии, что время не истекает ) выделит эту память обработчику запросов, после чего обработка запросов возобновится. Если обработчик запросов ошибается в оценке объема памяти, запрашиваемого у SQLOS, ему может потребоваться выполнить «разлив на диск»операция, при которой данные временно записываются в базу данных tempdb в промежуточной форме. Страницы, которые были записаны в базу данных tempdb, будут разблокированы после их записи в базу данных tempdb, чтобы освободить место для чтения других страниц в памяти. В конце концов, процесс запроса вернется к данным, хранящимся в базе данных tempdb, с разбивкой по страницам при использовании фиксации, на страницы в буфере, помеченные как свободные.
Я, несомненно, пропускаю множество очень технических деталей в приведенном выше резюме, но я думаю, что это отражает суть того, как SQL Server может обрабатывать больше данных, чем помещается в памяти.
источник
Я не могу говорить о том, что именно ваш запрос будет делать в этом сценарии, но SQL Server имеет несколько вариантов в зависимости от того, сколько нужно.
Лучший способ узнать, что произойдет, - создать сценарий в среде разработчика и выяснить это.
источник
Чтобы ответить на эту конкретную часть, позвольте мне рассказать вам, как это делается. Страницы имеют размер 8 КБ. Когда вы запускаете запрос, запрашивающий большой набор данных и требующий, чтобы многочисленные страницы были введены в память, SQL Server не будет приводить все страницы за один раз. Он найдет определенные страницы и принесет по одной 8КБ-страницы в память, прочитает данные из нее и даст вам результат, и теперь это будет продолжаться, если предположить, что он сталкивается с ситуацией, когда памяти меньше, в этом случае старые страницы будут сброшены диск как @Max указал. Как вы уже догадались, эта нехватка памяти может замедлить процесс, поскольку некоторое время будет потрачено на удаление старых страниц. Это где контрольно-пропускной пункт и Lazywriterвходит в картину. Ленивый писатель должен убедиться, что всегда есть немного свободной памяти, чтобы принести новые страницы на диск. При обнаружении низкого свободного буфера он срабатывает и создает свободные места для новых страниц.
РЕДАКТИРОВАТЬ
Память для объединения и фильтрации определяется еще до того, как запрос будет выполнен, и предположим, что действительно происходит нехватка памяти, а память, необходимая для выполнения операции, недоступна. Процессор SQL Server предоставит «необходимую память», которая
Так что, по крайней мере, запрос начнет выполняться, но во время выполнения вполне вероятно, что промежуточный результат передается в Tempdb, что делает его медленным. Я настоятельно рекомендую вам прочитать Понимание Query Memory Grant
источник