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.