Indekser i MySQL er et meget komplekst dyr. Vi har tidligere dækket MySQL-indekser, men vi har aldrig dykket dybere ned i dem – det vil vi gøre i denne serie af blogindlæg. Dette blogindlæg skal fungere som en meget generel guide til indekser, mens de andre dele af disse serier vil dykke en lille smule dybere ned i disse emner.
Hvad er indekser?
Generelt, som allerede nævnt i et tidligere blogindlæg om indekser, er et indeks en alfabetisk liste over poster med referencer til de sider, hvor de er nævnt. I MySQL er et indeks en datastruktur, der oftest bruges til hurtigt at finde rækker. Du hører måske også udtrykket "nøgler" - det refererer også til indekser.
Hvad gør indekser?
I MySQL bruges indekser til hurtigt at finde rækker med specifikke kolonneværdier og til at forhindre gennemlæsning af hele tabellen for at finde rækker, der er relevante for forespørgslen. Indekser bruges mest, når de data, der er gemt i et databasesystem (f.eks. MySQL) bliver større, fordi jo større tabellen er, jo større er sandsynligheden for, at du kan få gavn af indekser.
MySQL-indekstyper
For så vidt angår MySQL, har du måske hørt om, at det har flere typer indekser:
-
Et B-Tree INDEX - et sådant indeks bruges ofte til at fremskynde SELECT-forespørgsler, der matcher en WHERE-sætning. Et sådant indeks kan bruges på felter, hvor værdier ikke behøver at være unikke, det accepterer også NULL-værdier.
-
ET FULLTEXT INDEX - et sådant indeks bruges til at bruge fuldtekstsøgningsmuligheder. Denne type indeks finder nøgleord i teksten i stedet for direkte at sammenligne værdier med værdierne i indekset.
-
ET UNIKT INDEKS bruges ofte til at fjerne duplikerede værdier fra en tabel. Håndhæver rækkeværdiernes unikke karakter.
-
En PRIMÆR NØGLE er også et indeks - det bruges ofte sammen med felter med en AUTO_INCREMENT-attribut. Denne type indeks accepterer ikke NULL-værdier, og når de først er indstillet, kan værdierne i kolonnen, som har en PRIMÆR NØGLE, ikke ændres.
-
ET FALDENDE INDEKS er et indeks, der gemmer rækker i faldende rækkefølge. Denne type indeks blev introduceret i MySQL 8.0 - MySQL vil bruge denne type indeks, når der anmodes om en faldende rækkefølge af forespørgslen.
Valg af optimale datatyper til indekser i MySQL
For så vidt angår indekser, er der også behov for at huske på, at MySQL understøtter en lang række datatyper, og nogle datatyper kan ikke bruges sammen med visse typer indekser (f.eks. FULLTEXT indekser kan kun bruges på tekstbaserede (CHAR, VARCHAR eller TEXT) kolonner - de kan ikke bruges på andre datatyper), så før du rent faktisk vælger indekserne til dit databasedesign, skal du beslutte dig for den datatype, du vil bruge på den pågældende kolonne (beslut hvilken slags dataklasse du vil gemme:skal du gemme tal? Strengværdier? Både tal og strengværdier? osv.), beslut dig derefter for rækkevidden af de værdier, du vil gemme (vælg den, du ikke tror, du vil overskride, da det kan være en tidskrævende opgave at øge datatypeområdet senere - vi anbefaler, at du vælger at bruge en simpel datatype), og hvis du ikke har til hensigt at bruge NULL værdier i dine kolonner, angiv dine felter som IKKE NULL, når du kan - når en nullbar co lumn er indekseret, kræver det en ekstra byte pr. indtastning.
Valg af optimale tegnsæt og samlinger til indekser i MySQL
Udover datatyper skal du også huske på, at hvert tegn i MySQL optager plads. For eksempel kan UTF-8-tegn tage et vilkårligt sted mellem 1 og 4 bytes hver, så du vil måske undgå at indeksere f.eks. 255 tegn og kun bruge f.eks. 50 eller 100 tegn for en bestemt kolonne.
Fordele og ulemper ved at bruge indekser i MySQL
Den største fordel ved at bruge indekser i MySQL er den øgede ydeevne af søgeforespørgsler, der matcher en WHERE-klausul - indekser fremskynder SELECT-forespørgsler, der matcher en WHERE-klausul, fordi MySQL ikke læser hele tabellen igennem for at finde rækker relevant for forespørgslen. Men husk på, at indekser har deres egne ulemper. De vigtigste er som følger:
-
Indekser optager diskplads.
-
Indekser forringer ydeevnen af INSERT-, UPDATE- og DELETE-forespørgsler - når data opdateres, skal indekset være opdateret sammen med det.
-
MySQL beskytter dig ikke mod at bruge flere typer indekser på samme tid. Du kan med andre ord bruge en PRIMÆR NØGLE, et INDEX og et UNIKT INDEX på samme kolonne - MySQL beskytter dig ikke mod at lave sådan en fejl.
Hvis du har mistanke om, at nogle af dine forespørgsler bliver langsommere, kan du overveje at tage et kig på fanen Query Monitor i ClusterControl - ved at aktivere forespørgselsmonitoren kan du se, hvornår en bestemt forespørgsel sidst blev set og dens maksimum og gennemsnitlig udførelsestid, som kan hjælpe dig med at vælge de bedste indekser til dit bord.
Hvordan vælger man det bedste indeks at bruge?
For at vælge det bedste indeks at bruge, kan du bruge MySQLs indbyggede mekanismer. For eksempel kan du bruge forespørgselsforklaringen - EXPLAIN-forespørgslen. Den vil forklare hvilken tabel der bruges, om den har partitioner eller ej, hvilke indekser der er mulige at bruge og hvilken nøgle (indeks) der bruges. Det vil også returnere indekslængden og antallet af rækker, din forespørgsel returnerer:
mysql> EXPLAIN SELECT * FROM demo_table WHERE demo_field = ‘demo’\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: demo_table
partitions: NULL
type: ref
possible_keys: demo_field
key: demo_field
key_len: 1022
ref: const
rows: 1
filtered: 100.00
Extra: NULL
1 row in set, 1 warning (0.00 sec)
I dette tilfælde skal du huske på, at indekser ofte bruges til at hjælpe MySQL med effektivt at hente data, når datasæt er større end normalt. Hvis dit bord er lille, behøver du måske ikke bruge indekser, men hvis du ser, at dine tabeller bliver større og større, er der stor sandsynlighed for, at du kan få gavn af et indeks.
For at vælge det bedste indeks at bruge til dit specifikke scenarie, skal du dog huske på, at indekser også kan være en førende årsag til ydeevneproblemer. Husk på, at hvorvidt MySQL effektivt vil bruge indekserne eller ej afhænger af et par faktorer, herunder designet af dine forespørgsler, indekserne i brug, typerne af indekser i brug, også din databasebelastning på det tidspunkt, hvor forespørgslen udføres og andet. Her er et par ting at overveje, når du bruger indekser i MySQL:
-
Hvor meget data har du? Måske er noget af det overflødigt?
-
Hvilke forespørgsler bruger du? Ville dine forespørgsler bruge LIKE-klausuler? Hvad med at bestille?
-
Hvilken slags indeks skal du bruge for at forbedre ydeevnen af dine forespørgsler?
-
Vil dine indekser være store eller små? Skal du bruge et indeks på et præfiks for kolonnen for at gøre dens størrelse mindre?
Det er værd at bemærke, at du sandsynligvis også bør undgå at bruge flere typer indekser (f.eks. et B-Tree-indeks, et UNIKT INDEX og en PRIMÆR NØGLE) i samme kolonne.
Forbedring af forespørgselsydeevne med indekser
For at forbedre forespørgselsydeevnen med indekser skal du tage et kig på dine forespørgsler - EXPLAIN-sætningen kan hjælpe med det. Generelt er her et par ting, du bør overveje, hvis du ønsker, at dine indekser skal forbedre ydeevnen af dine forespørgsler:
-
Spørg kun databasen om det, du har brug for. I de fleste tilfælde vil det være hurtigere at bruge SELECT-kolonnen end at bruge SELECT * (det er tilfældet uden også at bruge indekser)
-
Et B-træindeks kan være passende, hvis du søger efter nøjagtige værdier (f.eks. SELECT * FROM demo_table WHERE some_field ='x'), eller hvis du vil søge efter værdier ved hjælp af jokertegn (f.eks. SELECT * FROM demo_table WHERE some_field LIKE 'demo%' - i dette tilfælde skal du huske på, at brug af LIKE-forespørgsler med hvad som helst i begyndelsen af det kan gøre det mere skade end gavn - undgå at bruge LIKE-forespørgsler med et procenttegn foran den tekst, du søger - på den måde bruger MySQL muligvis ikke et indeks, fordi det ikke ved, hvad rækkeværdien begynder med) - men husk at et B-træindeks også kan bruges til kolonnesammenligninger i udtryk, der bruger lig med (=), mere end (>), mere end eller lig med (>=), mindre end (<), mindre end eller lig med (<=) eller MELLEM operatorer.
-
Et FULLTEXT-indeks kan være passende, hvis du finder dig selv at bruge fuldtekst (MATCH ... MOD( )) søgeforespørgsler eller hvis din database er designet på en sådan måde, at den kun bruger tekstbaserede kolonner - FULLTEXT indekser kan bruge TEXT, CHAR eller VARCHAR kolonner, de kan ikke bruges på andre typer kolonner.
-
Et dækkende indeks kan være nyttigt, hvis du vil køre forespørgsler uden yderligere I/O-læsninger på store tabeller . For at oprette et dækkende indeks skal du dække WHERE-, GROUP BY- og SELECT-sætningerne, der bruges af forespørgslen.
Vi vil nærmere se nærmere på typerne af indekser i de kommende dele af denne blogserie, men generelt, hvis du bruger forespørgsler som SELECT * FROM demo_table WHERE some_field ='x' et B-træ INDEX kan passe, hvis du bruger MATCH() AGAINST()-forespørgsler, bør du sandsynligvis kigge i et FULLTEXT-indeks, hvis din tabel har meget lange rækkeværdier, bør du sandsynligvis undersøge indeksering af en del af kolonnen.
Hvor mange indekser skal du have?
Hvis du nogensinde har brugt indekser til at forbedre ydeevnen af dine SELECT-forespørgsler, har du sikkert stillet dig selv et spørgsmål:hvor mange indekser skal du egentlig have? For at forstå dette skal du huske på følgende:
-
Indekser er normalt de mest effektive med store mængder data.
-
MySQL bruger kun ét indeks pr. hver SELECT-sætning i en forespørgsel (underforespørgsler ses som separate udsagn) - brug EXPLAIN-forespørgslen for at finde ud af, hvilke indekser der er mest effektive til de forespørgsler, du bruger.
-
Indekser bør gøre alle dine SELECT-sætninger hurtige nok uden at gå på kompromis med diskpladsen - "hurtigt nok" , er dog relativt, så du bliver nødt til at eksperimentere.
Indekser og lagermotorer
Når du beskæftiger dig med indekser i MySQL, skal du også huske på, at der kan være nogle former for begrænsninger, hvis du bruger forskellige motorer (f.eks. hvis du bruger MyISAM i modsætning til InnoDB). Vi vil gå mere i detaljer i en separat blog, men her er nogle ideer:
-
Det maksimale antal indekser pr. MyISAM- og InnoDB-tabeller er 64, det maksimale antal kolonner pr. indeks i begge lagermotorer er 16.
-
Den maksimale nøglelængde for InnoDB er 3500 bytes - den maksimale nøglelængde for MyISAM er 1000 bytes.
-
Fuldtekstindekserne har begrænsninger i visse lagringsmotorer - for eksempel har InnoDB fuldtekstindekserne 36 stopord, MyISAM stopordslisten er en lille smule større med 143 stopord. InnoDB udleder disse stopord fra variabelen innodb_ft_server_stopword_table, mens MyISAM udleder disse stopord fra filen storage/myisam/ft_static.c - alle ord, der findes i filen, vil blive behandlet som stopord.
-
MyISAM var den eneste lagringsmaskine med understøttelse af fuldtekstsøgemuligheder indtil MySQL 5.6 (MySQL 5.6. 4 for at være præcis) kom omkring, hvilket betyder, at InnoDB understøtter fuldtekstindekser siden MySQL 5.6.4. Når et FULLTEXT-indeks er i brug, finder det nøgleord i teksten i stedet for at sammenligne værdier direkte med værdierne i indekset.
-
Indekser spiller en meget vigtig rolle for InnoDB - InnoDB låser rækker, når den får adgang til dem, så et reduceret antal rækker InnoDB-adgange kan reducere låse.
-
MySQL giver dig mulighed for at bruge duplikerede indekser i samme kolonne.
-
Visse lagringsmotorer har visse standardtyper af indekser (f.eks. for MEMORY-lagringsmotoren er standardindekstypen hash )
Oversigt
I denne del om indekser i MySQL har vi gennemgået nogle generelle ting relateret til indekser i dette relationelle databasestyringssystem. I de kommende blogindlæg vil vi gennemgå nogle mere dybdegående scenarier for brug af indekser i MySQL, herunder brugen af indekser i visse storage-motorer osv. - vi vil også forklare, hvordan ClusterControl kan bruges til at nå dine præstationsmål i MySQL.