Det är långsamt eftersom det måste hitta den översta offset
rader och skanna de kommande 100. Inga mängder av optimering kommer att förändra det när du har att göra med stora förskjutningar.
Detta beror på att din fråga bokstavligen instruerar DB-motorn för att besöka många rader genom att använda offset 3900000
-- det är 3,9 miljoner rader. Alternativen för att påskynda detta något är inte många.
Supersnabb RAM, SSD, etc. kommer att hjälpa. Men du kommer bara att vinna med en konstant faktor på att göra det, vilket betyder att det bara sparkar burken nerför vägen tills du når en tillräckligt större offset.
Att se till att bordet passar in i minnet, med mycket mer att spara kommer också att hjälpa till med en större konstant faktor - förutom första gången. Men detta kanske inte är möjligt med en tillräckligt stor tabell eller index.
Att se till att du gör enbart index-skanningar kommer att fungera i viss utsträckning. (Se velis svar; det har många fördelar.) Problemet här är att du för alla praktiska ändamål kan tänka dig ett index som en tabell som lagrar en diskplats och de indexerade fälten. (Det är mer optimerat än så, men det är en rimlig första uppskattning.) Med tillräckligt många rader kommer du fortfarande att stöta på problem med en tillräckligt stor offset.
Att försöka lagra och bibehålla den exakta positionen för raderna kommer säkert också att bli ett dyrt tillvägagångssätt. (Detta föreslås av t.ex. benjist.) Även om det är tekniskt genomförbart, lider det av begränsningar liknande de som härrör från att använda MPTT med en trädstruktur:du kommer att vinna avsevärt på läsningar men kommer att sluta med alltför långa skrivtider när en nod infogas, uppdateras eller tas bort på ett sådant sätt att stora delar av data behöver uppdateras vid sidan av.
Som förhoppningsvis är tydligare finns det ingen riktig magisk kula när du har att göra med så här stora offset. Det är ofta bättre att titta på alternativa tillvägagångssätt.
Om du paginerar baserat på ID:t (eller ett datumfält, eller någon annan indexerbar uppsättning fält), skulle ett potentiellt knep (som används av blogspot, till exempel) vara att få din fråga att börja på en godtycklig punkt i indexet.
Med andra ord istället för:
example.com?page_number=[huge]
Gör något som:
example.com?page_following=[huge]
På så sätt håller du koll på var du är i ditt index, och frågan blir väldigt snabb eftersom den kan gå direkt till rätt startpunkt utan att plöja igenom en gazillion rader:
select * from foo where ID > [huge] order by ID limit 100
Naturligtvis tappar man förmågan att hoppa till t.ex. sida 3000. Men tänk på det här:när var sista gången du hoppade till ett stort sidnummer på en webbplats istället för att gå direkt till dess månatliga arkiv eller använda dess sökruta?
Om du paginerar men vill hålla sidan förskjuten på något sätt, är ytterligare ett tillvägagångssätt att förbjuda användningen av större sidnummer. Det är inte dumt:det är vad Google gör med sökresultat. När du kör en sökfråga ger Google dig ett uppskattat antal resultat (du kan få ett rimligt antal med explain
), och sedan låter dig bläddra bland de bästa tusen resultaten -- inget mer. De gör det bland annat av prestationsskäl -- just den du stöter på.