sql >> Database teknologi >  >> RDS >> Mysql

Hvordan får jeg MySQL til at bruge et INDEX til visningsforespørgsel?

Hvordan får du MySQL til at bruge et indeks til en visningsforespørgsel? Det korte svar, giv et indeks, som MySQL kan bruge.

I dette tilfælde er det optimale indeks sandsynligvis et "dækkende" indeks:

... ON highscores (player, happened_in, score)

Det er sandsynligt, at MySQL vil bruge det indeks, og EXPLAIN vil vise:"Using index" på grund af WHERE player = 24 (et lighedsprædikat på den forreste kolonne i indekset. GROUP BY happened_id (den anden kolonne i indekset), kan tillade MySQL at optimere det ved at bruge indekset for at undgå en sorteringsoperation. Herunder score kolonne i indekset vil tillade, at forespørgslen opfyldes fuldstændigt fra indekset, uden at skulle besøge (opsøge) de datasider, som indekset refererer til.

Det er det hurtige svar. Det længere svar er, at det er meget usandsynligt, at MySQL vil bruge et indeks med indledende kolonne happened_id for visningsforespørgslen.

Hvorfor visningen forårsager et ydeevneproblem

Et af de problemer, du har med MySQL-visningen, er, at MySQL ikke "skubber" prædikatet fra den ydre forespørgsel ned i view-forespørgslen.

Din ydre forespørgsel angiver WHERE happened_in = 2006 . MySQL-optimeringsværktøjet overvejer ikke prædikatet, når det kører den indre "view-forespørgsel". Denne forespørgsel til visningen udføres separat før den ydre forespørgsel. Resultatsættet fra udførelsen af ​​den forespørgsel bliver "materialiseret"; det vil sige, at resultaterne gemmes som en mellemliggende MyISAM-tabel. (MySQL kalder det en "afledt tabel", og det navn, de bruger, giver mening, når du forstår de operationer, som MysQL udfører.)

Den nederste linje er, at det indeks, du har defineret på happened_in bliver ikke brugt af MySQL, når det kører den forespørgsel, der danner visningsdefinitionen.

Efter den mellemliggende "afledte tabel" er oprettet, SÅ udføres den ydre forespørgsel ved at bruge den "afledte tabel" som en rækkekilde. Det er, når den ydre forespørgsel kører, at happened_in = 2006 prædikat vurderes.

Bemærk, at alle rækkerne fra visningsforespørgslen er gemt, hvilket (i dit tilfælde) er en række for HVER værdi af happened_in , ikke kun den, du angiver et lighedsprædikat på i den ydre forespørgsel.

Den måde, som view-forespørgsler behandles på, kan være "uventet" af nogle, og dette er en af ​​grundene til, at brug af "views" i MySQL kan føre til ydeevneproblemer sammenlignet med den måde, view-forespørgsler behandles af andre relationelle databaser.

Forbedring af visningsforespørgslens ydeevne med et passende dækkende indeks

Givet din visningsdefinition og din forespørgsel, ville det bedste, du får, være en "Brug af indeks"-adgangsmetode til visningsforespørgslen. For at få det skal du have et dækkende indeks, f.eks.

... ON highscores (player, happened_in, score).

Det er sandsynligvis det mest fordelagtige indeks (performancemæssigt) for din eksisterende visningsdefinition og din eksisterende forespørgsel. player kolonne er den førende kolonne, fordi du har et lighedsprædikat på den kolonne i visningsforespørgslen. happened_in kolonne er den næste, fordi du har en GROUP BY operation på den kolonne, og MySQL vil være i stand til at bruge dette indeks til at optimere GROUP BY operationen. Vi inkluderer også score kolonne, fordi det er den eneste anden kolonne, der refereres til i din forespørgsel. Det gør indekset til et "dækkende" indeks, fordi MySQL kan tilfredsstille den forespørgsel direkte fra indekssider uden behov for at besøge nogen sider i den underliggende tabel. Og det er så godt, som vi kommer ud af den forespørgselsplan:"Brug af indeks" uden "Brug af filersort".

Sammenlign ydeevne med selvstændig forespørgsel uden nogen afledt tabel

Du kan sammenligne udførelsesplanen for din forespørgsel med visningen i forhold til en tilsvarende selvstændig forespørgsel:

SELECT player
     , MAX(score) AS highest_score
     , happened_in
 FROM highscores
WHERE player = 24
  AND happened_in = 2006
GROUP
   BY player
    , happened_in

Den selvstændige forespørgsel kan også gøre brug af et dækkende indeks f.eks.

... ON highscores (player, happened_in, score)

men uden behov for at materialisere en mellemliggende MyISAM-tabel.

Jeg er ikke sikker på, at nogen af ​​de foregående giver et direkte svar på det spørgsmål, du stillede.

Sp:Hvordan får jeg MySQL til at bruge et INDEX til visningsforespørgsel?

A:Definer et passende INDEX, som visningsforespørgslen kan bruge.

Det korte svar er at give et "dækkende indeks" (indekset inkluderer alle kolonner, der henvises til i visningsforespørgslen). De førende kolonner i det indeks skal være de kolonner, der refereres til med lighedsprædikater (i dit tilfælde kolonnen player ville være en ledende kolonne, fordi du har en player = 24 prædikat i forespørgslen. Desuden skal de kolonner, der henvises til i GROUP BY, være ledende kolonner i indekset, hvilket gør det muligt for MySQL at optimere GROUP BY operation, ved at gøre brug af indekset i stedet for at bruge en sorteringsoperation.

Nøglepunktet her er, at view-forespørgslen dybest set er en selvstændig forespørgsel; resultaterne fra den forespørgsel gemmes i en mellemliggende "afledt" tabel (en MyISAM-tabel, der oprettes, når en forespørgsel mod visningen køres.

At bruge visninger i MySQL er ikke nødvendigvis en "dårlig idé", men jeg vil på det kraftigste advare dem, der vælger at bruge visninger i MySQL, til at være bevidste om, hvordan MySQL behandler forespørgsler, der refererer til disse synspunkter. Og den måde, MySQL behandler visningsforespørgsler på, adskiller sig (betydeligt) fra den måde, visningsforespørgsler håndteres af andre databaser (f.eks. Oracle, SQL Server).



  1. Indlæser .sql-filer fra PHP

  2. Android - Bedre tilgang til indlæsning af SD-KORT-billeder

  3. Sådan fungerer OBJECTPROPERTY() i SQL Server

  4. Hæver barren på MySQL, MariaDB, PostgreSQL og MongoDB Management