sql >> Database >  >> RDS >> Sqlserver

SQL-prestaties:WHERE versus WHERE(ROW_NUMBER)

Zoals anderen al hebben opgemerkt, leveren de zoekopdrachten verschillende resultaten op en vergelijken ze appels met peren.

Maar de onderliggende vraag blijft:wat is sneller:keyset-gedreven paging of rownumber-gedreven paging?

Toetsenset-paging

Keyset-gestuurde paging is gebaseerd op het onthouden van de bovenste en onderste toetsen van de laatst weergegeven pagina en het opvragen van de volgende of vorige reeks rijen, op basis van de bovenste/laatste toetsenset:

Volgende pagina:

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

Vorige pagina:

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

Deze benadering heeft twee belangrijke voordelen ten opzichte van de ROW_NUMBER-benadering, of ten opzichte van de equivalente LIMIT-benadering van MySQL:

  • is juist :in tegenstelling tot de op rijnummers gebaseerde benadering, verwerkt het correct nieuwe items en verwijderde items. Laatste rij van pagina 4 wordt niet weergegeven als eerste rij van pagina 5 alleen omdat rij 23 op pagina 2 in de tussentijd is verwijderd. Noch verdwijnen rijen op mysterieuze wijze tussen pagina's. Deze anomalieën komen vaak voor bij de op row_number gebaseerde benadering, maar de op sleutelset gebaseerde oplossing kan ze veel beter vermijden.
  • is snel :alle bewerkingen kunnen worden opgelost met een snelle rijpositionering gevolgd door een bereikscan in de gewenste richting

Deze benadering is echter moeilijk te implementeren, moeilijk te begrijpen voor de gemiddelde programmeur en niet ondersteund door de tools.

Rijnummer gestuurd

Dit is de gebruikelijke benadering die is geïntroduceerd met Linq-query's:

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

(of een vergelijkbare zoekopdracht met TOP)Deze aanpak is eenvoudig te implementeren en wordt ondersteund door tools (met name door Linq .Limit en .Take operators). Maar deze aanpak is gegarandeerd om de index te scannen om de rijen te tellen. Deze aanpak werkt meestal erg snel voor pagina 1 en vertraagt ​​geleidelijk naarmate de ene naar hogere en hogere paginanummers gaat.

Als bonus is het met deze oplossing heel eenvoudig om de sorteervolgorde te wijzigen (verander gewoon de OVER-clausule).

Al met al, gezien het gemak van de op ROW_NUMBER() gebaseerde oplossingen, de ondersteuning die ze hebben van Linq, de eenvoud om willekeurige orders te gebruiken voor gematigde datasets de op ROW_NUMBER gebaseerde oplossingen zijn voldoende. Voor grote en zeer grote datasets kan de ROW_NUMBER() ernstige prestatieproblemen veroorzaken.

Een ander ding om te overwegen is dat er vaak een duidelijk patroon van toegang is. Vaak zijn de eerste paar pagina's hot en worden pagina's na 10 in principe nooit bekeken (bijv. meest recente berichten). In dit geval kan de straf die optreedt met ROW_NUMBER() voor het bezoeken van onderste pagina's (weergavepagina's waarvoor een groot aantal rijen moet worden geteld om de rij met startresultaten te krijgen) worden genegeerd.

En tot slot is de paginering van de keyset geweldig voor woordenboeknavigatie, wat ROW_NUMBER() niet gemakkelijk kan accommoderen. Woordenboeknavigatie is waar gebruikers in plaats van paginanummers te gebruiken, naar bepaalde ankers kunnen navigeren, zoals alfabetletters. Typisch voorbeeld is een contact Rolodex-achtige zijbalk, u klikt op M en u navigeert naar de eerste klantnaam die begint met M.



  1. Hoe UTC_TIMESTAMP() werkt in MariaDB

  2. Standaardwaarden van parameters parseren met PowerShell - Deel 3

  3. Zeer beschikbare databases en clusters implementeren met ClusterControl

  4. Wat is een schema in SQL Server en hoe maak je een schema in SQL Server-database? - SQL Server / TSQL-zelfstudie, deel 27