През годините купчина пот на разработчиците е отишла за ефективно пейджинг набори от резултати. И все пак няма един отговор - зависи от вашия случай на употреба. Част от случая на използване е да получите страницата си ефективно, част е да разберете колко реда има в пълен набор от резултати. Така че съжалявам, ако се отклонявам малко от страниците, но двете са доста тясно свързани в съзнанието ми.
Има много стратегии, повечето от които са лоши, ако имате някакъв обем данни и не отговаряте на случая на употреба. Въпреки че това не е пълен списък, следват някои от опциите.....
Изпълнете отделно Count(*)
- изпълнете отделна заявка, която прави просто „изберете брой(*) от MyTable“
- просто и лесно за малка маса
- добре за нефилтрирана голяма таблица, която е или тясна, или има компактен негрупиран индекс, който можете да използвате
- се разваля, когато имате сложен
WHERE/JOIN
критерии, защото изпълняваWHERE/JOIN
два пъти е скъпо. - се разбива на широк индекс, защото броят на прочитанията нараства.
Комбинирайте ROW_Number() OVER()
и COUNT(1) OVER(PARTITION By 1)
- Това беше предложено от @RBarryYoung. Предимството му е, че е лесен за изпълнение и много гъвкав.
- Недостатъкът е, че има много причини това бързо да стане изключително скъпо.
- Например, в база данни, с която работя в момента, има медийна таблица с около 6000 реда. Не е особено широк, има целочислен клъстерен PK и, както и компактен уникален индекс. И все пак, прост
COUNT(*) OVER(PARTITION BY 1) as TotalRows
води до ~12 000 прочитания. Сравнете това с простSELECT COUNT(*) FROM Media
-- 12 прочитания. Удивителни.
Временни таблици/променливи на таблици
- Има много стратегии, които вземат набор от резултати и вмъкват подходящи ключове или сегменти от резултати във временни таблици/променливи на таблици.
- За малки/средни набори от резултати това може да осигури страхотни резултати.
- Този тип стратегия работи в почти всяка платформа/версия на SQL.
- Многократното опериране с набор от резултати (доста често изискване) също е лесно.
- Недостатъкът е, че когато работите с големи набори от резултати... вмъкването на няколко милиона реда във временна таблица има цена.
- Проблемът се усложнява, тъй като в система с голям обем натискът върху TempDB може да бъде доста важен фактор и временните таблици работят ефективно в TempDB.
Сума на Гаус / Число с двоен ред
- Тази идея разчита на подмножество на нещо, което математикът Гаус измисли (как да се сумира поредица от числа). Подмножеството е как да получите броя на редовете от всяка точка в таблицата.
- От поредица от числа (
Row_Number()
) броят на редовете за 1 до N е(N + 1) - 1
. Повече обяснения в линковете. - Формулата изглежда така, сякаш ще достигне само N, но ако се придържате към формулата, се случват интересни неща, можете да разберете броя на редовете от страница в средата на таблицата.
- Нетният резултат е, че правите
ROW_Number() OVER(Order by ID)
иROW_Number() OVER(Order by ID DESC)
след това сумирайте двете числа и извадете 1. - Използвайки моята медийна таблица като пример, моите четения спаднаха от 12 000 на около 75.
- В по-голяма страница в крайна сметка сте повтаряли данни много пъти, но отместването при четенията може да си заслужава.
- Не съм тествал това в твърде много сценарии, така че може да се разпадне в други сценарии.
Най-горе (@n) / ЗАДАДЕ БРОЙ РЕДОВ
- Това не са конкретни стратегии сами по себе си, а са оптимизации въз основа на това, което знаем за оптимизатора на заявки.
- Креативното използване на Top(@n) [top може да бъде променлива в SQL 2008] или SET ROWCOUNT може да намали работния ви набор ... дори ако изтегляте средна страница от набор с резултати, пак можете да стесните резултата
- Тези идеи работят поради поведението на оптимизатора на заявки ... сервизен пакет/актуална корекция може да промени поведението (въпреки че вероятно не).
- В някои случаи SET ROWCOUNT може да е малко по-точен
- Тази стратегия не отчита получаването на пълния брой редове, а само прави странирането по-ефективно
И така, какво трябва да прави разработчикът?
Чети добри човече, чети. Ето няколко статии, на които се опрях...
- По-ефективен метод за пейджинг през големи набори от резултати
- Оптимизиране на страниране от страна на сървъра - част I
- Оптимизиране на страниране от страна на сървъра - Част II
- Обяснение на сумата на Гаус
- Връщане на класирани резултати с Microsoft SQL Server 2005
- ROW_NUMBER() OVER Не е достатъчно бързо с голям набор от резултати
- Извличане на първите N записа от SQL заявка
- Сървърно страниране с помощта на SQL Server 2005
- Защо са логически четения за прозоречни агрегатни функции толкова високи?
Надявам се, че това помага.