sql >> Database teknologi >  >> RDS >> Sqlserver

SQL-ydeevne:WHERE vs WHERE(ROW_NUMBER)

Som andre allerede har påpeget, returnerer forespørgslerne forskellige resultater og sammenligner æbler med appelsiner.

Men det underliggende spørgsmål forbliver:hvilket er hurtigere:tastesætdrevet personsøgning eller rækkenummerdrevet personsøgning?

Tastersøgning

Tastesætdrevet personsøgning er afhængig af at huske top- og bundtasterne på den sidst viste side og anmode om det næste eller forrige sæt rækker baseret på det øverste/sidste nøglesæt:

Næste side:

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

Forrige side:

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

Denne tilgang har to hovedfordele i forhold til ROW_NUMBER-tilgangen eller i forhold til den tilsvarende LIMIT-tilgang i MySQL:

  • er korrekt :i modsætning til den rækkenummerbaserede tilgang håndterer den nye indtastninger og slettede poster korrekt. Sidste række på side 4 vises ikke som første række på side 5, bare fordi række 23 på side 2 blev slettet i mellemtiden. Heller ikke rækker forsvinder på mystisk vis mellem siderne. Disse uregelmæssigheder er almindelige med den rækkenummerbaserede tilgang, men den nøglesætbaserede løsning gør et meget bedre stykke arbejde med at undgå dem.
  • er hurtig :alle operationer kan løses med en hurtig rækkepositionering efterfulgt af en rækkeviddescanning i den ønskede retning

Denne tilgang er dog vanskelig at implementere, svært at forstå af den gennemsnitlige programmør og ikke understøttet af værktøjerne.

Rækkenummerdrevet

Dette er den almindelige tilgang introduceret med Linq-forespørgsler:

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

(eller en lignende forespørgsel ved hjælp af TOP) Denne fremgangsmåde er let at implementere og understøttes af værktøjer (specifikt af Linq .Limit og .Take operatører). Men denne tilgang er garanteret for at scanne indekset for at tælle rækkerne. Denne tilgang fungerer normalt meget hurtigt for side 1 og bliver gradvist langsommere, efterhånden som en går til højere og højere sidetal.

Som en bonus er det med denne løsning meget nemt at ændre sorteringsrækkefølgen (ændre blot OVER-klausulen).

Samlet set, givet de ROW_NUMBER() baserede løsningers lette, støtten de har fra Linq, enkelheden at bruge vilkårlige ordrer til moderate datasæt de ROW_NUMBER baserede løsninger er tilstrækkelige. For store og meget store datasæt kan ROW_NUMBER() opstå alvorlige ydeevneproblemer.

En anden ting at overveje er, at der ofte er et bestemt adgangsmønster. Ofte er de første par sider hotte, og sider efter 10 bliver stort set aldrig set (f.eks. de seneste indlæg). I dette tilfælde kan straffen, der opstår med ROW_NUMBER() for at besøge nederste sider (visningssider, for hvilke der skal tælles et stort antal rækker for at få startresultatrækken) ignoreres godt.

Og endelig er tastaturpagineringen fantastisk til ordbogsnavigation, som ROW_NUMBER() ikke nemt kan rumme. Ordbogsnavigation er, hvor brugere i stedet for at bruge sidenummer kan navigere til bestemte ankre, såsom alfabetbogstaver. Et typisk eksempel er en kontakt Rolodex-lignende sidebar, du klikker på M og du navigerer til det første kundenavn, der starter med M.



  1. SQL DROP-indeks, DROP-tabel og DROP-databaseerklæringer forklaret med eksempler

  2. Automatisk dataversionering i MariaDB Server 10.3

  3. Sådan sikrer du din PostgreSQL-database - 10 tips

  4. Hvad er forskellen mellem Scope_Identity(), Identity(), @@Identity og Ident_Current()?