sql >> Databasteknik >  >> RDS >> Sqlserver

SQL-prestanda:WHERE vs WHERE(ROW_NUMBER)

Som andra redan påpekat ger frågorna olika resultat och jämför äpplen med apelsiner.

Men den underliggande frågan kvarstår:vilket är snabbare:nyckeluppsättningsdriven personsökning eller radnummerdriven personsökning?

Nyckelsökning

Nyckeluppsättningsdriven personsökning bygger på att komma ihåg de övre och nedre tangenterna på den senast visade sidan och begära nästa eller föregående uppsättning rader, baserat på den övre/sista tangentuppsättningen:

Nästa sida:

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

Föregående sida:

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

Det här tillvägagångssättet har två huvudsakliga fördelar jämfört med ROW_NUMBER-metoden, eller över den motsvarande LIMIT-metoden för MySQL:

  • är rätt :till skillnad från den radnummerbaserade metoden hanterar den nya poster och raderade poster korrekt. Sista raden på sida 4 visas inte som första raden på sida 5 bara för att rad 23 på sida 2 raderades under tiden. Inte heller rader försvinner mystiskt mellan sidorna. Dessa avvikelser är vanliga med den radnummerbaserade metoden, men den nyckeluppsättningsbaserade lösningen gör ett mycket bättre jobb för att undvika dem.
  • är snabb :alla operationer kan lösas med en snabb radpositionering följt av en räckviddsskanning i önskad riktning

Detta tillvägagångssätt är dock svårt att implementera, svårt att förstå av den genomsnittlige programmeraren och stöds inte av verktygen.

Radnummerstyrd

Detta är det vanliga tillvägagångssättet som introduceras med Linq-frågor:

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

(eller en liknande fråga med TOP) Det här tillvägagångssättet är enkelt att implementera och stöds av verktyg (speciellt av Linq .Limit och .Take operatörer). Men detta tillvägagångssätt är garanterat för att skanna indexet för att räkna raderna. Det här tillvägagångssättet fungerar vanligtvis mycket snabbt för sida 1 och saktar gradvis ner när ettan går till högre och högre sidnummer.

Som en bonus, med denna lösning är det mycket enkelt att ändra sorteringsordningen (ändra helt enkelt OVER-satsen).

Sammantaget, med tanke på de enkla ROW_NUMBER()-baserade lösningarna, stödet de har från Linq, enkelheten att använda godtyckliga order för måttliga datamängder de ROW_NUMBER-baserade lösningarna är tillräckliga. För stora och mycket stora datamängder kan ROW_NUMBER() uppstå allvarliga prestandaproblem.

En annan sak att tänka på är att det ofta finns ett bestämt mönster för åtkomst. Ofta är de första sidorna heta och sidor efter 10 visas i princip aldrig (t.ex. de senaste inläggen). I det här fallet kan påföljden som inträffar med ROW_NUMBER() för att besöka de nedersta sidorna (visa sidor för vilka ett stort antal rader måste räknas för att få startresultatraden) ignoreras väl.

Och slutligen, tangentuppsättningspagineringen är utmärkt för ordboksnavigering, som ROW_NUMBER() inte kan hantera lätt. Ordboksnavigering är där istället för att använda sidnummer kan användare navigera till vissa ankare, som bokstäver i alfabetet. Ett typiskt exempel är en kontakt Rolodex som sidofält, du klickar på M och du navigerar till det första kundnamnet som börjar med M.



  1. Fel när vänteläge skulle läggas till

  2. Viktig PostgreSQL-övervakning - Del 1

  3. Hur man får aktuellt datum och tid (utan tidszon) i T-SQL

  4. Vad händer om du inte begår en transaktion till en databas (säg SQL Server)?