Как стать автором
Обновить

Комментарии 15

А зачем извлекать все данные? Можно же сразу определить сколько взять.
Вот например: ASP.NET MVC: PagedList
Или в LINQ напрямую использовать Skip & Take
Добавил ответ на ваш вопрос в текст топика, в UPD.
Интересно, а как применить CTE в LINQ? или только чистый SQL?
в linq наверное не получиться использовать CTE, по крайней мере не нашел способа
Даже не думал, что кто-то недавно открыл для себя ROW_NUMBER(), а до этого читал все данные и тащил их на клиента.
в MSSQL2011 (aka «Denali») появилось ORDER BY OFFSET х ROWS FETCH NEXT у ROWS ONLY (MSDN). Может кому пригодится, когда сервер собственно выпустят в продакшен…
1. А где «повторное использования результатов одного SQL запроса в другом». Однократное CTE позволяют, давая TE запросу, который следует за ним, но где повторное использование?
2. Зачастую SET ROWCOUNT оказывается гораздо эффективней.
3. Почему не использовать ROW_NUMBER без CTE?
4. Количество чтений совершенно не означает, что именно столько будет загружено на клиент. Своевременно закрытый IDataReader останавливает поток из TDS.
Не совсем понял, в чем именно SET ROWCOUNT эффективнее.
Что вы имеете в виду, говоря о том чтобы использовать Row_number без CTE, можете пример запроса привести?
Совершенно согласен, что количество чтений это не количество данных, которые придут на клиент. на клиент придет то, что извлечет второй запрос при использовании CTE, а количество чтений — это сколько 8к страниц данных SQL сервер прочитает с диска или из кэша, чем больше это число, тем больше ресурсов потребляет SQL Server и тем медленнее работает запрос к БД.
Вообще, проверить, насколько каждый SQL запрос эффективен, довольно просто: запустите запрос в SSMS, добавив перед ним SET STATISTICS IO ON, а после выполнения посмотрите количество логических чтений. так же можно посмотреть план выполнения.
Немного промахнулся кнопкой, ответ ниже.
Тем, что он не занимается расчетом ROW_NUMBER. А учитывая что в большинстве случаев пользователь дальше первых 2-3 страниц не уходит, ROW_NUMBER может стать из пушки по воробьям. Если же вы тестировали ROW_NUMBER внимательно, то должны знать, что на больших объемах данных он работает очень медленно.

Имею ввиду создание, на самом деле повторно используемых представлений, использование простых вложенных запросов.

MSSQL не буферизует все данные, которые собирается отдавать. Поэтому если TDS будет закрыт после некоторой порции данных, то чтение остальных осуществляться не будет.

Если вы запустите запрос в SMSS, то проанализируете процесс чтения в таком виде, в каком его предполагает SSMS. То есть от начала до конца или до момента, когда его принудительно прервут. А я говорю о совершенно другой стратегии извлечения данных.
лучше, конечно, разобрать конкретный пример и посмотреть как он работает. так и не понял как воспользоваться SET ROWCOUNT. (насколько помню, он возвращает количество извлеченных запросом строк)

Насколько мне известно SSMS все же выдает фактическую информацию об операциях чтения. Если мы остановим обработку в DataReader, то SQL Server все равно выполнит у себя в памяти и в своих процессах запрос полностью, может быть, использование TOP N позволит ограничить операции чтения.

Что касается вложенных запросов, то часто эти запросы выполняются многократно, тем самым генерируя излишние операции чтения, CTE в этом плане хорош тем, что запрос CTE (первый в примере) выполняется только один раз, результаты сохраняет в опреативной памяти и затем обрабатывает в следующим запросе.
Да чтож я сегодня все промахиваюсь)) Ответ ниже.
Возвращает @@ROWOCUNT, а SET ROWCOUNT лимитирует количество записей.

Что значит выполнить запрос полностью? Если я сделаю select * from table, где table — терабайтная таблица, то он зарезервирует терабайт RAM? На самом деле все несколько сложнее. Клиент может отправить так называемый Attention request, чтобы инициировать остановку выполнения запроса. Правда сделать он это может только после получения TDS-пакета полностью и вполне могут проскочить еще пакеты до получения Attention aknowledgement, так что остановится он инертно (мера инертности обычно пропорционально настройкам сетевых буферов). Но остановится.

Вложенные запросы и CTE — просто разный языковой синтаксис одного и того же. В плане запроса мы увидим привычные сканы и в большинстве примеров дадут абсолютно одинаковые планы запросов, что в CTE, что во вложенных запросах. Фраза «запросы выполняются многократно» — это вообще что-то из области мистики.
@@ROWCOUNT возвращает количество строк предыдущей операции, использовать его внутри запроса для получения номеров строк не получается.

По поводу многократно выполняющихся подзапросов — такое можно увидеть, если просматривать план выполнения запросов. Например, такое бывает при JOINах методом Nested Loop
Третий раз повторяю. SET ROWCOUNT. Не @@ROWCOUNT. Нужно записи с 50 по 100 — сделали SET ROWCOUNT 100, 50 первых записей скипнули. Вообще, это азбука, обсуждается со времен древнего ASP.

Вы хотите сказать, что планировщик, увидев CTE магическим образом развернет join+nested loop в один скан? И оптимизатор в случае с вложенным запросом пропустит такую фантастическую возможность? Очень бы хотелось видеть пример.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Изменить настройки темы

Истории