SQL blev designet til at være et deklarativt sprog, ikke et proceduresprog. Så forespørgselsoptimeringsværktøjet bør ikke overveje rækkefølgen af where-klausulens prædikater ved at bestemme, hvordan de skal anvendes.
Jeg vil nok forenkle den følgende diskussion af en SQL-forespørgselsoptimering. Jeg skrev for et år siden, i denne retning (det var tonsvis af sjov!). Hvis du virkelig vil grave i moderne forespørgselsoptimering, kan du se Dan Tows SQL Tuning , fra O'Reilly.
I en simpel SQL-forespørgselsoptimering bliver SQL-sætningen først kompileret i et træ af relationel algebra operationer. Disse operationer tager hver en eller flere tabeller som input og producerer en anden tabel som output. Scan er en sekventiel scanning, der læser en tabel ind fra databasen. Sortér producerer en sorteret tabel. Vælg producerer en tabel, hvis rækker er valgt fra en anden tabel i henhold til en eller anden udvælgelsesbetingelse. Projekt producerer en tabel med kun visse kolonner i en anden tabel. Tværprodukt tager to tabeller og producerer en outputtabel, der er sammensat af enhver tænkelig parring af deres rækker.
Forvirrende nok er SQL SELECT-sætningen kompileret til en relationel algebra Projekt , mens WHERE-sætningen bliver til en relationel algebra Vælg . FROM-sætningen bliver til en eller flere Joins , der hver tager to borde ind og producerer et bord ud. Der er andre relationelle algebra-operationer, der involverer sætforening, skæringspunkt, forskel og medlemskab, men lad os holde det enkelt.
Dette træ trænger virkelig til at blive optimeret. For eksempel, hvis du har:
select E.name, D.name
from Employee E, Department D
where E.id = 123456 and E.dept_id = D.dept_id
med 5.000 medarbejdere fordelt på 500 afdelinger, vil eksekvering af et uoptimeret træ blindt producere alle mulige kombinationer af én medarbejder og én afdeling (et krydsprodukt ) og derefter Vælg ud af kun den ene kombination, der var nødvendig. Scan af medarbejder vil producere en 5.000 registreringstabel, Scan of Department vil producere en 500 registreringstabel, Cross Product af disse to tabeller vil producere en 2.500.000 registreringstabel, og Vælg på E.id vil tage det 2.500.000 postbord og kassere alle undtagen én, den post, der var ønsket.
[Virkelige forespørgselsprocessorer vil selvfølgelig prøve ikke at materialisere alle disse mellemtabeller i hukommelsen.]
Så forespørgselsoptimeringsværktøjet går rundt i træet og anvender forskellige optimeringer. Den ene er at opdele hver Vælg ind i en kæde af valg , en for hver af de originale Vælg 's øverste niveau betingelser, dem og-ed sammen. (Dette kaldes "konjunktiv normalform".) Derefter den enkelte mindre Vælger flyttes rundt i træet og slås sammen med andre relationelle algebraoperationer for at danne mere effektive.
I ovenstående eksempel trykker optimeringsværktøjet først på Vælg på E.id =123456 nede under det dyre Cross Product operation. Det betyder Krydsproduktet producerer bare 500 rækker (en for hver kombination af den pågældende medarbejder og en afdeling). Derefter Vælg på øverste niveau for E.dept_id =D.dept_id filtrerer de 499 uønskede rækker fra. Ikke dårligt.
Hvis der er et indeks på medarbejders id-felt, kan optimeringsværktøjet kombinere Scan af medarbejder med Vælg på E.id =123456 for at danne et hurtigt indeks Opslag . Det betyder, at kun én medarbejderrække læses ind i hukommelsen fra disken i stedet for 5.000. Tingene ser op.
Den sidste store optimering er at tage Vælg på E.dept_id =D.dept_id og kombiner det med Cross Product . Dette gør det til en relationel algebra Equijoin operation. Dette gør ikke meget i sig selv. Men hvis der er et indeks på Department.dept_id, så er det lavere niveau sekventielle Scan af afdelingen, der fodrer Equijoin kan omdannes til et meget hurtigt indeks Opslag af vores ene medarbejders afdelingsrekord.
Mindre optimeringer involverer at skubbe Projekt driften nede. Hvis det øverste niveau af din forespørgsel kun skal bruge E.name og D.name, og betingelserne kræver E.id, E.dept_id og D.dept_id, så skal Scan operationer behøver ikke at bygge mellemliggende tabeller med alle de andre kolonner, hvilket sparer plads under udførelsen af forespørgslen. Vi har forvandlet en frygtelig langsom forespørgsel til to indeksopslag og ikke meget andet.
For at komme mere i retning af det oprindelige spørgsmål, lad os sige, at du har:
select E.name
from Employee E
where E.age > 21 and E.state = 'Delaware'
Det uoptimerede relationelle algebratræ ville, når det blev udført, scanne de 5.000 ansatte og producere f.eks. de 126 i Delaware, der er ældre end 21. Forespørgselsoptimeringsværktøjet har også en grov idé om værdierne i databasen. Den ved måske, at E.state-kolonnen har de 14 stater, som virksomheden har lokationer i, og noget om E.age-fordelingerne. Så først ser den, om begge felter er indekseret. Hvis E.state er det, giver det mening at bruge det indeks til blot at udvælge det lille antal medarbejdere, som forespørgselsbehandleren har mistanke om, er i Delaware baseret på dens seneste beregnede statistik. Hvis kun E.age er det, beslutter forespørgselsprocessoren sandsynligvis, at det ikke er det værd, da 96 % af alle medarbejdere er 22 år og ældre. Så hvis E.state er indekseret, bryder vores forespørgselsprocessor Vælg og fusionerer E.state ='Delaware' med Scan for at gøre det til en meget mere effektiv indeksscanning .
Lad os sige i dette eksempel, at der ikke er nogen indekser på E.state og E.age. Den kombinerede Vælg operation finder sted efter den sekventielle "Scan" af medarbejder. Gør det en forskel, hvilken betingelse i Vælg gøres først? Sandsynligvis ikke meget. Forespørgselsprocessoren kan efterlade dem i den oprindelige rækkefølge i SQL-sætningen, eller den kan være en smule mere sofistikeret og se på den forventede udgift. Fra statistikken ville den igen konstatere, at tilstanden E.state ='Delaware' burde være mere selektiv, så den ville vende betingelserne og gøre det først, så der kun er 126 E.age> 21 sammenligninger i stedet for 5.000 . Eller den indser måske, at sammenligninger af strengeligheder er meget dyrere end heltalssammenligninger og lader rækkefølgen være i fred.
I hvert fald er alt dette meget komplekst, og din syntaktiske tilstandsrækkefølge vil sandsynligvis ikke gøre en forskel. Jeg ville ikke bekymre mig om det, medmindre du har et reelt problem med ydeevnen, og din databaseleverandør bruger tilstandsrækkefølgen som et tip.