SQL Order of Operations – I vilken ordning MySQL utför frågor?
Klicka för att starta, gratis.
Att känna till bitarna och bytesna i en SQL-förfrågnings operationsordning kan vara mycket värdefullt, eftersom det kan underlätta skrivandet av nya förfrågningar, samtidigt som det är mycket fördelaktigt när man försöker optimera en SQL-förfrågan.
Om du letar efter den korta versionen är detta den logiska operationsordningen, även känd som exekveringsordningen, för en SQL-fråga:
- FRÅN, inklusive JOINs
- WHERE
- GROUP BY
- HAVING
- WINDOW-funktioner
- SELECT
- DISTINCT
- UNION
- ORDER BY
- LIMIT och OFFSET
Men verkligheten är inte så enkel eller rak. Som vi sa definierar SQL-standarden exekveringsordningen för de olika SQL-frågeklausulerna. Med det sagt utmanar moderna databaser redan denna standardordning genom att tillämpa vissa optimeringsknep som kan ändra den faktiska exekveringsordningen, även om de måste sluta med att returnera samma resultat som om de körde frågan i standardutförarordningen.
Varför skulle de göra det? Tja, det kan vara dumt om databasen först hämtar alla data som nämns i FROM-klausulen (inklusive JOINs), innan den tittar på WHERE-klausulen och dess index. Dessa tabeller kan innehålla mycket data, så du kan föreställa dig vad som kommer att hända om databasens optimerare skulle hålla sig till den traditionella ordningen för en SQL-fråga.
Låt oss titta på var och en av SQL-frågans delar i enlighet med deras exekveringsordning.
FROM och JOINs
Tabellerna som anges i FROM-klausulen (inklusive JOINs), kommer att utvärderas först, för att bestämma hela den arbetsuppsättning som är relevant för frågan. Databasen kommer att slå samman data från alla tabeller, enligt JOINs ON-klausulerna, samtidigt som den hämtar data från underfrågorna, och kanske till och med skapar några tillfälliga tabeller för att hålla de data som returneras från underfrågorna i denna klausul.
I många fall kommer dock databasens optimerare att välja att utvärdera WHERE-delen först, för att se vilken del av arbetsmängden som kan utelämnas (helst med hjälp av index), så att den inte blåser upp datamängden för mycket om den inte verkligen behöver göra det.
Where-klausulen
Where-klausulen kommer att vara den andra som utvärderas, efter FROM-klausulen. Vi har den fungerande datamängden på plats och nu kan vi filtrera data enligt villkoren i WHERE-klausulen.
Dessa villkor kan inkludera referenser till data och tabeller från FROM-klausulen, men kan inte inkludera några referenser till alias som definierats i SELECT-klausulen, eftersom dessa data och alias ännu inte ”existerar” i det sammanhanget, eftersom den klausulen ännu inte har utvärderats av databasen.
En vanlig fallgrop för WHERE-klausulen är också att försöka filtrera bort aggregerade värden i WHERE-klausulen, till exempel med denna klausul: ”WHERE sum(available_stock) > 0”. Det här uttalandet kommer att misslyckas med att utföra frågan, eftersom aggregeringar kommer att utvärderas senare i processen (se avsnittet GROUP BY nedan). För att tillämpa filtreringsvillkor på aggregerade data bör du använda HAVING-klausulen och inte WHERE-klausulen.
GROUP BY-klausulen
När vi nu har filtrerat datamängden med hjälp av WHERE-klausulen kan vi aggregera data enligt en eller flera kolumner som förekommer i GROUP BY-klausulen. Att gruppera data är egentligen att dela upp dem i olika delar eller hinkar, där varje hink har en nyckel och en lista över rader som matchar den nyckeln. Att inte ha en GROUP BY-klausul är som att lägga alla rader i en enda stor hink.
När du har aggregerat data kan du nu använda aggregeringsfunktioner för att returnera ett värde per grupp för var och en av hinkarna. Sådana aggregeringsfunktioner är COUNT, MIN, MAX, SUM och andra.
HAVING-klausulen
När vi nu har grupperat data med hjälp av GROUP BY-klausulen kan vi använda HAVING-klausulen för att filtrera bort vissa hinkar. Villkoren i HAVING-klausulen kan hänvisa till aggregeringsfunktionerna, så exemplet som inte fungerade i WHERE-klausulen ovan kommer att fungera utmärkt i HAVING-klausulen: ”HAVING sum(available_stock) > 0”.
Eftersom vi redan har grupperat data kan vi inte längre få tillgång till de ursprungliga raderna vid den här tidpunkten, så vi kan bara tillämpa villkor för att filtrera hela hinkar och inte enskilda rader i en hink.
Som vi nämnde i tidigare avsnitt kan aliaser som definierats i SELECT-klausulen inte heller nås i avsnittet, eftersom de ännu inte utvärderats av databasen (detta gäller i de flesta databaser).
Window-funktioner
Om du använder Window-funktioner är detta den punkt där de exekveras. Precis som grupperingsmekanismen utför fönsterfunktioner också en beräkning på en uppsättning rader. Den största skillnaden är att när du använder Window-funktioner behåller varje rad sin egen identitet och grupperas inte i en hink med andra liknande rader.
Window-funktioner kan bara användas i antingen SELECT- eller ORDER BY-klausulen. Du kan använda aggregeringsfunktioner inom fönsterfunktionerna, till exempel:
SUM(COUNT(*)) OVER ()
SELECT-klausul
När vi nu är klara med att kasta bort rader från datamängden och gruppera data kan vi välja de data vi vill hämta från frågan till klientsidan. Du kan använda kolumnnamn, aggregeringar och underfrågor i SELECT-klausulen. Tänk på att om du använder en referens till en aggregeringsfunktion, t.ex. COUNT(*) i SELECT-klausulen, är det bara en referens till en aggregering som redan har ägt rum när grupperingen ägde rum, så själva aggregeringen sker inte i SELECT-klausulen, utan detta är bara en referens till dess resultatuppsättning.
Nyckelordet DISTINCT
Syntaxen för nyckelordet DISTINCT är lite förvirrande, eftersom nyckelordet tar plats före kolumnnamnen i SELECT-klausulen. Men den faktiska DISTINCT-operationen äger rum efter SELECT. När du använder nyckelordet DISTINCT kommer databasen att kasta bort rader med dubbla värden från de återstående rader som finns kvar efter att filtrering och aggregering ägt rum.
Nyckelordet UNION
Nyckelordet UNION kombinerar resultatuppsättningarna från två sökningar till en resultatuppsättning. De flesta databaser låter dig välja mellan UNION DISTINCT (som tar bort dubbla rader från den kombinerade resultatuppsättningen) eller UNION ALL (som bara kombinerar resultatuppsättningarna utan att tillämpa någon kontroll av dubblering).
Du kan tillämpa sortering (ORDER BY) och begränsning (LIMIT) på UNION:s resultatuppsättning, på samma sätt som du kan tillämpa det på en vanlig fråga.
ORDER BY-klausulen
Sortering sker när databasen har hela resultatuppsättningen klar (efter filtrering, gruppering, borttagning av dubbletter). När vi har det kan databasen nu sortera resultatuppsättningen med hjälp av kolumner, valda alias eller aggregeringsfunktioner, även om de inte ingår i de valda uppgifterna. Det enda undantaget är när man använder nyckelordet DISTINCT, som förhindrar sortering efter en kolumn som inte är vald, eftersom resultatuppsättningens ordning i så fall blir odefinierad.
Du kan välja att sortera data med hjälp av en fallande (DESC) ordning eller en stigande (ASC) ordning. Ordningen kan vara unik för varje del av ordningen, så följande är giltigt: ORDER BY firstname ASC, age DESC
LIMIT och OFFSET
I de flesta användningsfall (med undantag för några få som rapportering) vill vi kasta alla rader utom de första X raderna i sökresultatet. LIMIT-klausulen, som utförs efter sortering, gör det möjligt att göra just detta. Dessutom kan du välja vilken rad som ska börja hämta data från och hur många som ska uteslutas, med hjälp av en kombination av nyckelorden LIMIT och OFFSET. Följande exempel hämtar 50 rader som börjar med rad 100: LIMIT 50 OFFSET 100
Klicka för att börja, gratis.