Sqlserver
 sql >> Baza danych >  >> RDS >> Sqlserver

Wydajność SQL:WHERE vs WHERE (ROW_NUMBER)

Jak już zauważyli inni, zapytania zwracają różne wyniki i porównują jabłka z pomarańczami.

Ale podstawowe pytanie pozostaje:co jest szybsze:stronicowanie oparte na zestawach kluczy czy stronicowanie oparte na numerach wierszy?

Stronicowanie zestawu kluczy

Stronicowanie oparte na zestawach kluczy polega na zapamiętywaniu górnych i dolnych klawiszy ostatniej wyświetlanej strony oraz żądaniu następnego lub poprzedniego zestawu wierszy na podstawie górnego/ostatniego zestawu kluczy:

Następna strona:

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

Poprzednia strona:

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

To podejście ma dwie główne zalety w porównaniu z podejściem ROW_NUMBER lub równoważnym podejściem LIMIT w MySQL:

  • jest poprawny :w przeciwieństwie do podejścia opartego na numerach wierszy, poprawnie obsługuje nowe wpisy i usunięte wpisy. Ostatni wiersz strony 4 nie jest wyświetlany jako pierwszy wiersz strony 5 tylko dlatego, że wiersz 23 na stronie 2 został w międzyczasie usunięty. Wiersze nie znikają też w tajemniczy sposób między stronami. Te anomalie są powszechne w podejściu opartym na liczbie wierszy, ale rozwiązanie oparte na zestawie kluczy znacznie lepiej radzi sobie z ich unikaniem.
  • jest szybki :wszystkie operacje można rozwiązać za pomocą szybkiego pozycjonowania wierszy, po którym następuje skanowanie zakresu w żądanym kierunku

Jednak to podejście jest trudne do wdrożenia, trudne do zrozumienia dla przeciętnego programisty i nieobsługiwane przez narzędzia.

Na podstawie numeru wiersza

Jest to powszechne podejście wprowadzone w zapytaniach Linq:

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

(lub podobne zapytanie przy użyciu TOP) To podejście jest łatwe do wdrożenia i jest obsługiwany przez narzędzia (w szczególności przez operatorów Linq .Limit i .Take). Ale takie podejście jest gwarantowane aby zeskanować indeks w celu zliczenia wierszy. To podejście działa zwykle bardzo szybko na stronie 1 i stopniowo zwalnia, gdy jedna przechodzi do coraz wyższych numerów stron.

Jako bonus, dzięki temu rozwiązaniu bardzo łatwo jest zmienić kolejność sortowania (po prostu zmień klauzulę OVER).

Ogólnie rzecz biorąc, biorąc pod uwagę łatwość rozwiązań opartych na ROW_NUMBER(), wsparcie, jakie mają ze strony Linq, prostotę użycia arbitralnych zamówień dla umiarkowanymi zestawami danych rozwiązania oparte na ROW_NUMBER są odpowiednie. W przypadku dużych i bardzo dużych zestawów danych ROW_NUMBER() może powodować poważne problemy z wydajnością.

Inną rzeczą do rozważenia jest to, że często istnieje określony wzorzec dostępu. Często pierwsze kilka stron jest gorących, a strony po 10 w zasadzie nigdy nie są przeglądane (np. najnowsze posty). W takim przypadku kara, która pojawia się przy ROW_NUMBER() za odwiedzenie dolnych stron (wyświetlanych stron, dla których trzeba policzyć dużą liczbę wierszy, aby uzyskać początkowy wiersz wyników) może zostać zignorowana.

I wreszcie, podział na strony zestawu kluczy jest świetny do nawigacji po słowniku, której ROW_NUMBER() nie może łatwo pomieścić. Nawigacja po słowniku polega na tym, że zamiast używać numeru strony, użytkownicy mogą nawigować do określonych kotwic, takich jak litery alfabetu. Typowym przykładem jest kontaktowy pasek boczny w stylu Rolodex, klikasz M i przechodzisz do pierwszej nazwy klienta, która zaczyna się na 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. Proaktywne kontrole kondycji programu SQL Server, część 3:ustawienia instancji i bazy danych

  2. Piętro data w serwerze SQL

  3. Co to jest LEN() w SQL Server?

  4. Funkcje zdefiniowane przez użytkownika programu SQL Server

  5. Zamień pojedyncze cudzysłowy w SQL Server