sql >> Databasteknik >  >> RDS >> Mysql

Påverkar ordningen på fälten i en WHERE-sats prestanda i MySQL?

SQL designades för att vara ett deklarativt språk, inte ett procedurspråk. Så frågeoptimeraren borde inte överväga ordningen för where-klausulens predikat när du bestämmer hur de ska tillämpas.

Jag kommer förmodligen att förenkla följande diskussion om en SQL-frågeoptimerare. Jag skrev för ett år sedan, i den här stilen (det var jättekul!). Om du verkligen vill gräva i modern frågeoptimering, se Dan Tows SQL Tuning , från O'Reilly.

I en enkel SQL-frågeoptimerare kompileras SQL-satsen först till ett träd av relationell algebra operationer. Dessa operationer tar var och en en eller flera tabeller som indata och producerar en annan tabell som utdata. Skanna är en sekventiell skanning som läser in en tabell från databasen. Sortera producerar en sorterad tabell. Välj producerar en tabell vars rader väljs från en annan tabell enligt något urvalsvillkor. Projekt producerar en tabell med endast vissa kolumner i en annan tabell. Krossprodukt tar två tabeller och producerar en utdatatabell som består av alla tänkbara parning av deras rader.

Förvirrande nog kompileras SQL SELECT-satsen till en relationalgebra Projekt , medan WHERE-satsen förvandlas till en relationalgebra Select . FROM-satsen förvandlas till en eller flera Joins , var och en tar två bord in och producerar ett bord ut. Det finns andra relationella algebraoperationer som involverar uppsättningsförening, skärningspunkt, skillnad och medlemskap, men låt oss hålla detta enkelt.

Det här trädet måste verkligen optimeras. Till exempel, om 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 anställda på 500 avdelningar, kommer exekvering av ett ooptimerat träd blint att producera alla möjliga kombinationer av en anställd och en avdelning (en korsprodukt ) och sedan Välj ut bara den kombination som behövdes. Scan of Employee kommer att producera en 5 000 posttabell, Scan of Department kommer att producera en tabell med 500 poster, Cross Product av dessa två tabeller kommer att producera en 2 500 000 posttabell, och Välj på E.id kommer att ta det 2 500 000-postbordet och kassera alla utom en, posten som önskades.

[Verkliga frågeprocessorer kommer naturligtvis att försöka att inte materialisera alla dessa mellantabeller i minnet.]

Så frågeoptimeraren går i trädet och tillämpar olika optimeringar. En är att dela upp varje Välj i en kedja av utvalda , en för var och en av de ursprungliga Välj s högsta nivå villkor, de och-ed tillsammans. (Detta kallas "konjunktiv normalform".) Sedan de enskilda mindre Väljer flyttas runt i trädet och slås samman med andra relationella algebraoperationer för att bilda mer effektiva.

I exemplet ovan trycker optimeraren först på Välj på E.id =123456 lägre än den dyra korsprodukten drift. Det betyder korsprodukten producerar bara 500 rader (en för varje kombination av den anställde och en avdelning). Sedan Välj på toppnivån för E.dept_id =D.dept_id filtrerar bort de 499 oönskade raderna. Inte illa.

Om det finns ett index på anställds id-fält, kan optimeraren kombinera Scan av anställd med Välj på E.id =123456 för att bilda ett snabbt index Lookup . Detta innebär att endast en anställd rad läses in i minnet från disk istället för 5 000. Saker och ting ser upp.

Den sista stora optimeringen är att ta Välj på E.dept_id =D.dept_id och kombinera det med Krossprodukten . Detta förvandlar det till en relationalgebra Equijoin drift. Detta gör inte så mycket av sig självt. Men om det finns ett index på Department.dept_id, är den lägre nivån sekventiella Scan av avdelningen som matar Equijoin kan förvandlas till ett mycket snabbt index Lookup av vår en anställds avdelningsrekord.

Mindre optimeringar innebär att du trycker på Projekt verksamheten ner. Om den översta nivån i din fråga bara behöver E.name och D.name, och villkoren behöver E.id, E.dept_id och D.dept_id, då Scan operationer behöver inte bygga mellanliggande tabeller med alla andra kolumner, vilket sparar utrymme under exekveringen av frågan. Vi har förvandlat en fruktansvärt långsam fråga till två indexuppslagningar och inte mycket annat.

För att komma mer till den ursprungliga frågan, låt oss säga att du har:

select E.name 
from Employee E 
where E.age > 21 and E.state = 'Delaware'

Det ooptimerade relationalgebraträdet, när det körs, skulle skanna in de 5 000 anställda och producera, säg, de 126 i Delaware som är äldre än 21. Frågeoptimeraren har också en grov uppfattning om värdena i databasen. Den kanske vet att kolumnen E.stat har de 14 staterna som företaget har platser i, och något om E.age-fördelningarna. Så först ser den om något av fälten är indexerat. Om E.state är det, är det vettigt att använda det indexet för att bara välja ut det lilla antal anställda som frågeprocessorn misstänker finns i Delaware baserat på dess senast beräknade statistik. Om bara E.age är det, bestämmer frågeprocessorn sannolikt att det inte är värt det, eftersom 96 % av alla anställda är 22 år och äldre. Så om E.state indexeras bryter vår frågeprocessor Välj och slår samman E.state ='Delaware' med Scan för att göra det till en mycket effektivare Indexsökning .

Låt oss säga i det här exemplet att det inte finns några index på E.state och E.age. Den kombinerade Välj operationen sker efter den sekventiella "Scan" av anställd. Gör det någon skillnad vilket villkor i Välj görs först? Förmodligen inte mycket. Frågeprocessorn kan lämna dem i den ursprungliga ordningen i SQL-satsen, eller så kan den vara lite mer sofistikerad och titta på den förväntade kostnaden. Från statistiken skulle den återigen finna att villkoret E.state ='Delaware' borde vara mer mycket selektivt, så det skulle vända villkoren och göra det först, så att det bara finns 126 E.age> 21 jämförelser istället för 5 000 . Eller den kanske inser att jämförelser av stränglikhet är mycket dyrare än heltalsjämförelser och låter ordningen vara ifred.

I vilket fall som helst är allt detta mycket komplext och din syntaktiska tillståndsordning är mycket osannolik att göra någon skillnad. Jag skulle inte bry mig om det om du inte har ett verkligt prestandaproblem och din databasleverantör använder villkorsordningen som ett tips.



  1. startar postgresql och pgadmin i Windows utan installation

  2. Filtrerade index och forcerad parametrering (redux)

  3. Formaterar DATE i oracle

  4. tomcat7 - jdbc datasource - Detta är mycket sannolikt att skapa en minnesläcka