Hur får man MySQL att använda ett index för en vyfråga? Det korta svaret, ge ett index som MySQL kan använda.
I det här fallet är det optimala indexet troligen ett "täckande" index:
... ON highscores (player, happened_in, score)
Det är troligt att MySQL kommer att använda det indexet, och EXPLAIN kommer att visa:"Using index"
på grund av WHERE player = 24
(ett likhetspredikat på den inledande kolumnen i indexet. GROUP BY happened_id
(den andra kolumnen i indexet), kan tillåta MySQL att optimera det genom att använda indexet för att undvika en sorteringsoperation. Inklusive score
kolumnen i indexet kommer att tillåta frågan att tillfredsställa helt från indexet, utan att behöva besöka (slå upp) datasidorna som refereras av indexet.
Det är det snabba svaret. Det längre svaret är att MySQL är mycket osannolikt att använda ett index med ledande kolumn happened_id
för visningsfrågan.
Varför vyn orsakar prestandaproblem
Ett av problemen du har med MySQL-vyn är att MySQL inte "trycker" predikatet från den yttre frågan ner till vyfrågan.
Din yttre fråga anger WHERE happened_in = 2006
. MySQL-optimeraren tar inte hänsyn till predikatet när den kör den inre "view-frågan". Den frågan för vyn körs separat, före den yttre frågan. Resultaten från exekveringen av den frågan "materialiseras"; det vill säga resultaten lagras som en mellanliggande MyISAM-tabell. (MySQL kallar det en "derived table", och det namnet de använder är vettigt när du förstår operationerna som MysQL utför.)
Summan av kardemumman är att indexet du har definierat på happened_in
används inte av MySQL när den kör frågan som bildar vydefinitionen.
Efter att den mellanliggande "derived table" har skapats, DÅ exekveras den yttre frågan med den "derived table" som en radkälla. Det är när den yttre frågan körs som happened_in = 2006
predikatet utvärderas.
Observera att alla rader från vyfrågan lagras, vilket (i ditt fall) är en rad för VARJE värde av happened_in
, inte bara den du anger ett likhetspredikat på i den yttre frågan.
Sättet som vyfrågor bearbetas kan vara "oväntat" av vissa, och detta är en anledning till att användning av "vyer" i MySQL kan leda till prestandaproblem, jämfört med hur vyfrågor bearbetas av andra relationsdatabaser.
Förbättra prestanda för vyfrågan med ett lämpligt täckande index
Med tanke på din vydefinition och din fråga, skulle det bästa du kommer att få vara en "Using index"-åtkomstmetod för vyfrågan. För att få det behöver du ett täckande index, t.ex.
... ON highscores (player, happened_in, score).
Det är sannolikt det mest fördelaktiga indexet (prestandamässigt) för din befintliga vydefinition och din befintliga fråga. player
kolumn är den ledande kolumnen eftersom du har ett likhetspredikat på den kolumnen i vyfrågan. happened_in
kolumn är nästa, eftersom du har en GROUP BY-operation på den kolumnen, och MySQL kommer att kunna använda detta index för att optimera GROUP BY-operationen. Vi inkluderar även score
kolumn, eftersom det är den enda andra kolumnen som refereras till i din fråga. Det gör indexet till ett "täckande" index, eftersom MySQL kan tillgodose den frågan direkt från indexsidor, utan att behöva besöka några sidor i den underliggande tabellen. Och det är lika bra som att vi kommer att ta oss ur den frågeplanen:"Använder index" utan "Använder filsortering".
Jämför prestanda med fristående fråga utan härledd tabell
Du kan jämföra exekveringsplanen för din fråga med vyn jämfört med en likvärdig fristående fråga:
SELECT player
, MAX(score) AS highest_score
, happened_in
FROM highscores
WHERE player = 24
AND happened_in = 2006
GROUP
BY player
, happened_in
Den fristående frågan kan också använda sig av ett täckande index, t.ex.
... ON highscores (player, happened_in, score)
men utan att behöva materialisera en mellanliggande MyISAM-tabell.
Jag är inte säker på att något av föregående ger ett direkt svar på frågan du ställde.
F:Hur får jag MySQL att använda ett INDEX för visningsfråga?
S:Definiera ett lämpligt INDEX som vyfrågan kan använda.
Det korta svaret är att tillhandahålla ett "täckande index" (index inkluderar alla kolumner som refereras till i vyfrågan). De ledande kolumnerna i det indexet bör vara de kolumner som refereras med likhetspredikat (i ditt fall kolumnen player
skulle vara en ledande kolumn eftersom du har en player = 24
predikat i frågan. Dessutom bör kolumnerna som refereras till i GROUP BY vara ledande kolumner i indexet, vilket gör att MySQL kan optimera GROUP BY
operation, genom att använda indexet istället för att använda en sorteringsoperation.
Nyckelfrågan här är att vyfrågan i grunden är en fristående fråga; resultaten från den frågan lagras i en mellanliggande "härledd" tabell (en MyISAM-tabell som skapas när en fråga mot vyn körs.
Att använda vyer i MySQL är inte nödvändigtvis en "dålig idé", men jag vill starkt varna de som väljer att använda vyer i MySQL att vara MEDvetna om hur MySQL behandlar frågor som refererar till dessa vyer. Och hur MySQL behandlar vyfrågor skiljer sig (avsevärt) från hur vyfrågor hanteras av andra databaser (t.ex. Oracle, SQL Server).