sql >> Database >  >> RDS >> Mysql

Heeft de volgorde van velden in een WHERE-clausule invloed op de prestaties in MySQL?

SQL is ontworpen als een declaratieve taal, niet als een procedurele taal. Dus de query-optimizer moet niet houd rekening met de volgorde van de predikaten van de waar-clausule bij het bepalen hoe ze moeten worden toegepast.

Ik ga de volgende bespreking van een SQL-query-optimizer waarschijnlijk te eenvoudig maken. Ik schreef een jaar geleden, langs deze lijnen (het was heel leuk!). Als je je echt wilt verdiepen in moderne query-optimalisatie, bekijk dan Dan Tow's SQL Tuning , van O'Reilly.

In een eenvoudige SQL-query-optimizer wordt de SQL-instructie eerst gecompileerd in een boom van relationele algebra activiteiten. Deze bewerkingen nemen elk een of meer tabellen als invoer en produceren een andere tabel als uitvoer. Scannen is een sequentiële scan die een tabel uit de database inleest. Sorteren produceert een gesorteerde tabel. Selecteer produceert een tabel waarvan de rijen zijn geselecteerd uit een andere tabel volgens een selectievoorwaarde. Project produceert een tabel met alleen bepaalde kolommen van een andere tabel. Kruisproduct neemt twee tabellen en produceert een uitvoertabel die is samengesteld uit elke denkbare combinatie van hun rijen.

Verwarrend genoeg is de SQL SELECT-component gecompileerd tot een relationele algebra Project , terwijl de WHERE-component verandert in een relationele algebra Selecteer . De FROM-component verandert in een of meer Joins , waarbij elk twee tafels innam en er één uit produceerde. Er zijn andere relationele algebra-bewerkingen met betrekking tot verzamelingen unie, intersectie, verschil en lidmaatschap, maar laten we het simpel houden.

Deze boom moet echt geoptimaliseerd worden. Als u bijvoorbeeld het volgende heeft:

select E.name, D.name 
from Employee E, Department D 
where E.id = 123456 and E.dept_id = D.dept_id

met 5.000 medewerkers in 500 afdelingen, zal het uitvoeren van een niet-geoptimaliseerde boom blindelings alle mogelijke combinaties opleveren van één medewerker en één afdeling (een Cross Product ) en dan Selecteer uit net die ene combinatie die nodig was. De Scan van de werknemer zal een tabel met 5.000 records produceren, de Scan of Department zal een tabel met 500 records produceren, de Cross Product van die twee tabellen zal een 2.500.000 recordtabel opleveren, en de Select op E.id zal die 2.500.000 recordtafel nemen en op één na alle records weggooien, het record dat werd gezocht.

[Echte query-processors zullen natuurlijk proberen niet al deze tussenliggende tabellen in het geheugen te materialiseren.]

Dus de query-optimizer loopt door de boom en past verschillende optimalisaties toe. Een daarvan is om elke Selecteer . op te splitsen in een keten van Selecteert , één voor elk van de originele Selecteer 's hoogste niveau voorwaarden, die en-ed samen. (Dit wordt "conjunctieve normaalvorm" genoemd.) Vervolgens wordt de individuele kleinere Selecteert worden in de boom verplaatst en samengevoegd met andere relationele algebra-bewerkingen om efficiëntere te vormen.

In het bovenstaande voorbeeld drukt de optimizer eerst op de Select op E.id =123456 beneden het dure Cross Product operatie. Dit betekent het Kruisproduct produceert slechts 500 rijen (één voor elke combinatie van die werknemer en één afdeling). Dan is het bovenste niveau Selecteer for E.dept_id =D.dept_id filtert de 499 ongewenste rijen uit. Niet slecht.

Als er een index is op het ID-veld van de werknemer, kan de optimizer de Scan combineren van werknemer met de Selecteer op E.id =123456 om een ​​snelle index te vormen Lookup . Dit betekent dat er slechts één rij Werknemers vanaf schijf in het geheugen wordt ingelezen in plaats van 5.000. De zaken gaan omhoog.

De laatste grote optimalisatie is het nemen van de Select op E.dept_id =D.dept_id en combineer het met het Cross Product . Dit verandert het in een relationele algebra Equijoin operatie. Dit doet op zich niet veel. Maar als er een index is op Department.dept_id, dan is de sequentiële Scan op een lager niveau van de afdeling die de Equijoin voedt kan worden omgezet in een zeer snelle index Lookup van het afdelingsrecord van onze ene medewerker.

Kleinere optimalisaties omvatten het pushen van Project operaties naar beneden. Als het hoogste niveau van uw zoekopdracht alleen E.name en D.name nodig heeft, en de voorwaarden E.id, E.dept_id en D.dept_id, dan is de Scan bewerkingen hoeven geen tussenliggende tabellen te bouwen met alle andere kolommen, waardoor er ruimte wordt bespaard tijdens de uitvoering van de query. We hebben een vreselijk trage zoekopdracht omgezet in twee indexzoekopdrachten en niet veel anders.

Om meer naar de oorspronkelijke vraag te gaan, laten we zeggen dat je het volgende hebt:

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

De niet-geoptimaliseerde relationele algebra-boom zou, wanneer uitgevoerd, de 5.000 werknemers scannen en bijvoorbeeld de 126 in Delaware produceren die ouder zijn dan 21. De query-optimizer heeft ook een ruw idee van de waarden in de database. Het weet misschien dat de E.state-kolom de 14 staten bevat waarin het bedrijf vestigingen heeft, en iets over de E.age-distributies. Dus eerst wordt gekeken of een van beide velden is geïndexeerd. Als E.state dat wel is, is het logisch om die index te gebruiken om op basis van de laatst berekende statistieken het kleine aantal werknemers te selecteren waarvan de vermoede dat de queryprocessor zich in Delaware bevindt. Als alleen E.age dat is, besluit de query-processor waarschijnlijk dat het het niet waard is, aangezien 96% van alle werknemers 22 jaar en ouder is. Dus als E.state is geïndexeerd, verbreekt onze queryprocessor de Select en voegt de E.state ='Delaware' samen met de Scan om er een veel efficiëntere Index Scan van te maken .

Laten we in dit voorbeeld zeggen dat er geen indexen zijn op E.state en E.age. De gecombineerde Selecteer bewerking vindt plaats na de opeenvolgende "Scan" van de werknemer. Maakt het verschil welke voorwaarde in de Selecteer eerst gedaan? Waarschijnlijk niet veel. De queryprocessor kan ze in de oorspronkelijke volgorde in de SQL-instructie laten staan, of het kan een beetje geavanceerder zijn en kijken naar de verwachte kosten. Uit de statistieken zou opnieuw blijken dat de voorwaarde E.state ='Delaware' selectiever zou moeten zijn, dus zou het de voorwaarden omkeren en dat eerst doen, zodat er slechts 126 E.age> 21 vergelijkingen zijn in plaats van 5.000 . Of hij realiseert zich misschien dat vergelijkingen van stringgelijkheid veel duurder zijn dan vergelijkingen met gehele getallen en laat de volgorde met rust.

In ieder geval is dit allemaal erg complex en het is zeer onwaarschijnlijk dat je syntactische conditievolgorde een verschil zal maken. Ik zou me er geen zorgen over maken, tenzij je een echt prestatieprobleem hebt en je databaseleverancier de voorwaardevolgorde als hint gebruikt.



  1. MySQL:Tabel afkappen binnen transactie?

  2. Deel 2 – Een groot databasediagram organiseren?

  3. Hoe kan ik een datetime in SQL Server afkappen?

  4. MySql:kolommen weergeven maar alles uitsluiten behalve de veldnamen