Sqlserver
 sql >> база данни >  >> RDS >> Sqlserver

SQL производителност:WHERE срещу WHERE(ROW_NUMBER)

Както други вече посочиха, заявките връщат различни резултати и сравняват ябълки с портокали.

Но основният въпрос остава:кое е по-бързо:пейджиране, управлявано от набор от клавиши, или пейджиране, управлявано от номера на ред?

Пейджинг на клавишите

Страничната страница, управлявана от набор от клавиши, разчита на запомнянето на горния и долния клавиш на последната показана страница и изискване на следващия или предишен набор от редове въз основа на горния/последния набор от ключове:

Следваща страница:

select top (<pagesize>) ...
from <table>
where key > @last_key_on_current_page
order by key;

Предишна страница:

select top (<pagesize>)
from <table>
where key < @first_key_on_current_page
order by key desc;

Този подход има две основни предимства пред подхода ROW_NUMBER или пред еквивалентния LIMIT подход на MySQL:

  • еправилно :за разлика от подхода, базиран на номера на редове, той правилно обработва нови записи и изтрити записи. Последният ред на страница 4 не се показва като първи ред на страница 5, само защото ред 23 на страница 2 беше изтрит междувременно. Нито пък редовете мистериозно изчезват между страниците. Тези аномалии са често срещани при подхода, базиран на row_number, но решението, базирано на набор от ключове, върши много по-добра работа при избягването им.
  • ебърз :всички операции могат да бъдат решени с бързо позициониране на редове, последвано от сканиране на диапазон в желаната посока

Този подход обаче етруден за изпълнение, трудно разбираемо от обикновения програмист и не се поддържа от инструментите.

Управляван номер на ред

Това е общият подход, въведен със заявките на Linq:

select ...
from (
  select ..., row_number() over (...) as rn
  from table)
where rn between @firstRow and @lastRow;

(или подобна заявка, използваща TOP) Този подход е лесен за внедряване и се поддържа от инструменти (по-специално от операторите Linq .Limit и .Take). Но този подход е гарантиран за да сканирате индекса, за да преброите редовете. Този подход обикновено работи много бързо за страница 1 и постепенно се забавя, когато едната преминава към все по-високи номера на страници.

Като бонус, с това решение е много лесно да промените реда на сортиране (просто променете клаузата OVER).

Като цяло, като се има предвид лекотата на решенията, базирани на ROW_NUMBER(), подкрепата, която имат от Linq, простотата за използване на произволни поръчки за умерени набори от данни базираните на ROW_NUMBER решения са подходящи. За големи и много големи набори от данни ROW_NUMBER() може да възникне сериозни проблеми с производителността.

Друго нещо, което трябва да имате предвид, е, че често има определен модел на достъп. Често първите няколко страници са горещи и страници след 10 по принцип никога не се разглеждат (напр. най-новите публикации). В този случай наказанието, което настъпва с ROW_NUMBER() за посещение на най-долните страници (показване на страници, за които трябва да се преброят голям брой редове, за да се получи началният ред с резултати), може да бъде добре игнорирано.

И накрая, пагинацията на набора от клавиши е чудесна за навигация в речник, която ROW_NUMBER() не може лесно да поеме. Навигацията в речника е мястото, където вместо да използват номера на страницата, потребителите могат да навигират до определени котви, като букви от азбуката. Типичен пример е странична лента за контакт с Rolodex, щракнете върху M и отидете до името на първия клиент, което започва с M.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Вземете записите от миналия месец в SQL сървър

  2. 7 факта за синонимите на SQL Server, които трябва да знаете

  3. SSMS версия 18 – няма диаграми на база данни

  4. Android достъп до отдалечена SQL база данни

  5. Преструктуриране и реорганизиране на индекса на SQL Server