sql >> Databasteknik >  >> RDS >> Mysql

mysql:mycket enkelt SELECT id ORDER BY LIMIT kommer inte att använda INDEX som förväntat (?!)

Indexuppslagningar är efter värde , inte efter position . Ett index kan söka efter ett värde 2955900, men du ber inte om det. Du ber om att frågan ska börja med en förskjutning av den 2955900:e raden i tabellen.

Optimeraren kan inte anta att alla primära nyckelvärden är konsekutiva. Så det är ganska troligt att den 2955900:e raden har ett värde som är mycket högre än så.

Även om primärnyckelvärdena är konsekutiva kan du ha ett WHERE-villkor som bara matchar till exempel 45 % av raderna. I så fall skulle id-värdet på raden 2955900 vara way förbi id-värdet 2955900.

Med andra ord, en indexsökning av id-värdet 2955900 kommer inte att leverera den 2955900:e raden.

Så MySQL kan inte använda indexet för en limits offset. Det måste skanna raderna för att räkna dem tills den når raderna förskjutning+gräns.

MySQL har optimeringar relaterade till LIMIT , men det handlar mer om att stoppa en tabellsökning när den har nått antalet rader som ska returneras. Optimeraren kan fortfarande rapportera i en EXPLAIN-plan att den förväntar sig att den kan måste skanna hela tabellen.

Ett frekvent missförstånd om KRAFTINDEX är att det tvingar fram användningen av ett index. :-) Faktum är att frågan inte kan använd ett index (eller om de tillgängliga indexen inte har någon fördel för den här frågan), har FORCE INDEX ingen effekt.

Angående din kommentar:

Paginering är ett frekvent förbud av datadrivna webbapplikationer. Trots hur vanlig den här funktionen är är den inte lätt att optimera. Här är några tips:

  • Varför frågar du med offset 2955900? Förväntar du dig verkligen att användare ska sålla igenom så många sidor? De flesta användare ger upp efter några sidor (exakt hur många beror på typen av applikation och data).

  • Minska antalet frågor. Din pagineringsfunktion kan hämta de första 5-10 sidorna, även om den bara visar den första sidan för användaren. Cachelagra de andra sidorna, med antagandet att användaren kommer att gå igenom några sidor. Endast om de går förbi den cachade uppsättningen sidor måste din app göra en ny fråga. Du kan till och med cachelagra alla 10 sidor i Javascript i klientens webbläsare så att klicka på "Nästa" är omedelbart för dem (åtminstone för de första sidorna).

  • Sätt inte en "Sista"-knapp på något användargränssnitt, eftersom folk kommer att klicka på den av nyfikenhet. Observera att Google har en "Nästa"-knapp men inte en "Sista"-knapp. Så själva användargränssnittet avskräcker människor från att köra ineffektiva frågor med höga förskjutningar.

  • Om användaren avancerar en sida i taget, använd det högsta id-värdet som returnerades på föregående sida i WHERE-satsen i nästa sidas fråga. d.v.s. följande gör använd indexet, även utan något FORCE INDEX-tips:

    SELECT * FROM thistable WHERE id > 544 LIMIT 20
    



  1. Logga varje MySQL-fråga till en fil genom att aktivera den allmänna inloggningen MAMP

  2. Hur hanterar man db-anslutningar på servern?

  3. Installera AdventureWorks-databasen Samples i Microsoft SQL Server 2012

  4. MySQL ger ett okänt kolumn 'user.id' i 'field list'-fel med Djangos automatiska id