Lägger du till MySQL i din lista över databasfärdigheter? Då är MySQL UPDATE-satsen ett av kommandona du behöver lära dig.
Vi fortsätter vår resa till MySQL ur SQL Server-synpunkt. Det började med CREATE TABLE, följt av INSERT, och det senaste stycket handlade om DELETE. Idag är UPDATE vår fokuspunkt.
Skillnaderna är subtila och lätta att lära sig. Men precis som i de tidigare artiklarna är vårt mål att du snabbt ska komma igång. Men innan vi fortsätter, låt oss klargöra dessa saker:
- Exemplen som används här kördes på MySQL 8.0.23 med InnoDB-lagringsmotorn.
- Vi använde SQL Server 2019.
Förbered provdata
Vi kan inte fortsätta utan exempeldata. Jag skulle vilja sätta T-SQL-utvecklare hemma i den här övningen. Så låt oss importera några välbekanta tabeller till AdventureWorks exempeldatabas från SQL Server:
- Produkt
- SalesOrderHeader
- Försäljningsorderdetaljer
För att importera dessa tabeller till MySQL använde jag dbForge Studio för MySQL. Här är stegen:
- Skapa en ny databas som heter adventureworks2019 .
- Högerklicka på adventureworks2019 och välj Verktyg .
- Välj Importera data . Ett nytt fönster visas.
- Välj ODBC . Du måste skapa ett användar-DSN för att ansluta till din SQL Server och AdventureWorks databas.
- Klicka på Nästa .
- Välj tabellen du behöver importera, MySQL-anslutningen och måldatabasen (adventureworks2019 ).
- Klicka på Nästa .
- Ändra kolumninställningarna. Du kan också se exempeldata. Du kan hoppa över detta genom att klicka på Nästa eller ändra inställningarna som du vill.
- Klicka på Importera .
- Importera nästa tabell genom att följa samma instruktioner på skärmen.
- Klicka på Slutför .
Efter att ha importerat dessa tabeller är du nu redo för exemplen i den här artikeln. Så låt oss börja.
1. Grundläggande syntax
MySQL UPDATE-satsens syntax går så här:
UPDATE [LOW_PRIORITY] [IGNORE] table_references
SET assignment_list
[WHERE where_condition]
[ORDER BY ...]
[LIMIT row_count]
Jag kan nästan höra dig efter att ha läst syntaxen:LÅG PRIORITET, IGNORERA, BESTÄLLA EFTER, och LIMIT passar inte! Låt oss börja diskutera från toppen.
För det första är LOW_PRIORITY ett främmande nyckelord för oss eftersom SQL Server inte stöder det. Det är valfritt, men om du inkluderar det fördröjs uppdateringarna tills alla andra klienter inte läser tabellen.
Ett annat utomjordiskt nyckelord är IGNORE. Det är också valfritt, men om du inkluderar det och dubbletter uppstår kommer ett fel inte att uppstå. För fler ignorerbara fel, kolla in den här länken.
BESTÄLL sedan. Vi vet vad det är till för. Men prova det i SQL Server Management Studio så kommer snirkliga linjer att dyka upp under nyckelord.
Slutligen, LIMIT. Detta är samma sak som TOP i SQL Server. Mer av detta och BESTÄLL AV i ett senare avsnitt.
Dessa är de uppenbara skillnaderna. Läs vidare i de kommande två underavsnitten.
MySQL UPPDATERING Enstaka kolumn
Att uppdatera en enskild kolumn är nästan likadant. Så exemplet nedan kommer att ge samma resultat från båda databasplattformarna. Observera dock att istället för backticks använder SQL Server hakparenteser.
-- MySQL UPDATE single column
UPDATE `production.product`
SET ReorderPoint = 650
WHERE ProductID = 316;
Här är en likvärdig T-SQL-syntax:
-- T-SQL UPDATE single column
UPDATE [Production].[Product]
SET ReorderPoint = 650
WHERE ProductID = 316;
Värdet som tilldelas en kolumn kan vara vilket uttryck som helst med enstaka värden så länge som den returnerade typen är densamma som datatypen för kolumnen.
MySQL UPPDATERING Flera kolumner
Att uppdatera flera kolumner är också nästan likt T-SQL. Här är ett exempel:
UPDATE `production.product`
SET ReorderPoint = 650, SafetyStockLevel = 1200
WHERE ProductID = 316;
För att uppdatera flera kolumner, separera helt enkelt kolumn-värdepar med ett kommatecken. Återigen, den enda skillnaden här är backticks.
Än så länge är dessa uppdateringar för enstaka tabeller. Låt oss gå vidare till MySQL UPDATE från ett annat bord.
2. MySQL UPPDATERING med JOIN
Det finns mindre skillnader du kommer att se när du uppdaterar en tabell med joins. Det bästa sättet att visa detta är genom ett exempel på att använda 3 tabeller.
UPDATE `sales.salesorderdetail` sod
INNER JOIN `sales.salesorderheader` soh ON sod.SalesOrderID = soh.SalesOrderID
INNER JOIN `production.product` p ON sod.ProductID = p.ProductID
set UnitPrice = p.ListPrice
WHERE p.ProductID = 758
AND soh.OrderDate = '2012-04-30';
Observera att vissa satser är ordnade annorlunda jämfört med SQL Server. Joins visas först före SET-klausulen. Det finns ingen FROM-klausul heller. Som du kan förvänta dig kommer SQL Server Management Studio att sätta snirkliga linjer för den felande syntaxen. Se detta och den korrekta T-SQL-syntaxen i figur 1 nedan.
Före uppdateringen är enhetsprisvärdet 874,7940 som visas i figur 2.
Efter uppdateringen, UnitPrice uppdateras från Produkten tabellens ListPrice . Se figur 3.
Förutom INNER JOIN kan du använda LEFT eller RIGHT JOIN beroende på dina krav.
3. MySQL UPPDATERING med Subquery
Du kan använda MySQL UPDATE-satsen från en annan tabell med hjälp av en underfråga. Frågan med en join i föregående avsnitt kan skrivas om med hjälp av en underfråga. Resultaten blir desamma. Här kommer:
UPDATE `sales.salesorderdetail` sod
INNER JOIN `sales.salesorderheader` soh ON sod.SalesOrderID = soh.SalesOrderID
SET sod.UnitPrice = (select ListPrice from `production.product` WHERE ProductID = 758)
WHERE sod.ProductID = 758
AND soh.OrderDate = '2012-04-30';
Tillvägagångssättet är annorlunda, men resultatet är detsamma som i figur 3. Observera dock att underfrågan som används för att uppdatera en kolumn bör returnera 1 värde.
Det finns ett annat sätt att uttrycka detta MySQL UPDATE-uttalande.
4. MySQL UPPDATERING med CTE
Common Table Expressions (CTE) stöds i både MySQL och SQL Server. Om du inte är bekant med CTE, kolla in den tidigare artikeln.
Nu, här är motsvarande uttalande med CTE som används.
WITH priceIncrease AS
(
SELECT soh.SalesOrderID, p.ProductID, p.ListPrice
FROM `sales.salesorderdetail` sod
INNER JOIN `sales.salesorderheader` soh ON sod.SalesOrderID = soh.SalesOrderID
INNER JOIN `production.product` p ON sod.ProductID = p.ProductID
WHERE p.ProductID = 758
AND soh.OrderDate = '2012-04-30'
)
UPDATE `sales.salesorderdetail` s
INNER JOIN priceIncrease pi ON s.SalesOrderID = pi.SalesOrderID AND s.ProductID = pi.ProductID
SET s.UnitPrice = pi.ListPrice
SQL Server stöder samma koncept, men utan backticks. Resultatet blir detsamma som i figur 3.
Du kan fråga dig vilken av de tre metoderna som är bättre? Vi kommer att jämföra deras prestanda ytterligare.
5. MySQL UPPDATERING med LIMIT
MySQL UPDATE kan begränsa antalet rader som ska uppdateras med nyckelordet LIMIT. Anta att vi vill uppdatera 5 poster i Produkten tabell. Vi kan uttrycka uttalandet så här:
UPDATE `production.product` p
SET p.StandardCost = p.StandardCost + 10, p.ListPrice = p.ListPrice + 10
ORDER BY p.ProductID
LIMIT 5;
Detta kommer att sortera posterna baserat på ProduktID , och uppdatera sedan de första 5 posterna. Det slutar efter den 5:e posten.
SQL Serverns motsvarighet till LIMIT är TOP. Du kan dock inte bara ändra nyckelordet LIMIT till TOP och förvänta dig att det kommer att fungera i SQL Server. Här är den modifierade versionen i T-SQL som ger samma resultat:
UPDATE Production.Product
SET StandardCost += 10, ListPrice += 10
WHERE ProductID IN (SELECT TOP 5 ProductID
FROM Production.Product
ORDER BY ProductID)
Logiken är lite annorlunda. Den uppdaterar StandardCost och Listpris kolumner baserade på produkt-ID:n som finns i underfrågan. Underfrågan, å andra sidan, returnerar de första 5 posterna för Produkten tabell sorterad efter ProduktID .
Även om TOP också stöds i T-SQL-UPPDATERING, är ORDER BY inte det. Användning av TOP med UPDATE kommer alltså att ändra slumpmässiga poster. Ovanstående syntax är tillämplig för beställda poster med TOP.
MySQL UPPDATERING Prestanda
Tidigare hade vi ett UPDATE-uttalande med samma resultat även om vi använde olika metoder. Vi använde en JOIN, subquery och CTE. Vilken av dem kommer att prestera bäst?
Det finns också en exekveringsplan i MySQL med nyckelordet EXPLAIN. Syntaxen är så här:
EXPLAIN [FORMAT=JSON]
<SQL statement>
Utan JSON-formatet har du grundläggande information som tabeller, indexnycklar som används och rader skannade. När JSON-format är specificerat har du mer detaljerad information. dbForge Studio för MySQL innehåller en Query Profiler utöver resultatet av EXPLAIN. MySQL Workbench innehåller en Visual EXPLAIN där du kan se en grafisk vy av planen baserad på EXPLAIN FORMAT=JSON.
Nu när vi känner till kommandoradssatserna och de grafiska verktygen, hur kan vi använda dem för att jämföra olika metoder?
Innan vi fortsätter, låt mig vara ärlig. Min kunskap i SQL Server är högre än i MySQL. Jag kanske missar något på vägen eller har fel. Du kan fylla luckorna i avsnittet Kommentarer senare.
Dissekerar EXPLAIN-resultat för UPDATE med JOIN
Första gången jag körde MySQL UPDATE-satsen med JOIN tog det 11,3 sekunder för 24 rader uppdaterade. Otroligt, eller hur?
Här är vad som hände i dbForge Studio. Kolla in figur 4 nedan.
Vad säger figur 4 oss?
- De 3 tabellaliasen som används finns där. Alla 3 har åtkomsttyper av ALLA. Det betyder att MySQL använde Table Scan för alla 3.
- Titta på tangenten kolumn. Ingenting visas på alla tre tabellerna, vilket betyder att inga indexnycklar användes. Detta stöder föregående punkt i Tabellskanning.
- Slutligen, raderna kolumn. Den talar om hur många rader MySQL tror att den ska skanna för att uppnå det slutliga resultatet. För 24 uppdaterade rader skannades tusentals rader efter SalesOrderHeader och SalesOrderDetails . Under tiden, alla rader i Produkten tabellen skannades.
Jag kliade mig i huvudet när jag lärde mig detta. Jag insåg att när jag importerade tabeller från SQL Server importerades bara tabellstrukturen och data, inte indexen .
Så jag skapade lämpliga index och primärnycklar i dbForge Studio. Det här är vad jag skapade:
- Jag skapade Produkt-ID i Produkt tabell en primärnyckel.
- Jag har också lagt till SalesOrderID som en primärnyckel i SalesOrderHeader tabell. Sedan gjorde jag ett index för OrderDate också.
- Äntligen skapade jag SalesOrderDetailID i SalesOrderDetail tabell en primärnyckel. Jag har också lagt till ett index för SalesOrderID och Produkt-ID kolumner i den här tabellen.
Efter detta skapade jag en ny exekveringsplan för samma fråga för att se förbättringarna. Resultatet?
HASTIGHETSÖKNING EFTER ATT LÄGGT TILL INDEX
Utförandetiden minskade från 11,3 sekunder till 0,019 sekunder. Mycket coolt!
Låt oss kontrollera den nya planen med dbForge Studio i figur 5 nedan.
Vad säger figur 5 oss?
- Åtkomsten typer av 3 tabeller ändrades. De 2 värdena att undvika här är ALL och INDEX, speciellt på stora bord. ALL är Table Scan och INDEX är Index Scan.
- Nyckeln kolumn inkluderar nu de använda indexen. Det här är bra. Alla index som lagts till användes.
- raderna kolumn visar nu mindre siffror. Indexen som lades till minskade mycket I/O i vår fråga.
För mer information om EXPLAIN-detaljerna och värdena, läs den här officiella dokumentationen.
Men hur jämför detta med MySQL UPDATE med underfråga?
Dissekerar EXPLAIN-resultat för UPDATE med underfråga
Den tidigare frågan för att uppdatera Enhetspris kolumnen har ett annat frågealternativ, som använder en underfråga. Hur är det jämfört med JOIN? Kolla in figur 6 nedan.
Figur 6 visar:
- Värden för typ, nyckel och rader i kolumnen är desamma jämfört med att använda JOIN. Detta är logiskt eftersom det borde ha samma resultat.
- Körningstiden tog lite snabbare. Detta kommer dock inte att hända varje gång. Det beror på vilka resurser som finns tillgängliga för närvarande. Hastighetsskillnaden är också försumbar. Du kommer inte att känna det alls.
Ett annat sätt är att använda EXPLAIN FORMAT=JSON för att få mer information om planen. Vid kontroll är frågekostnaden (84,79) och kostnadsinformationsvärden desamma.
Låt oss nu jämföra det med MySQL UPDATE med CTE.
Dissekerar EXPLAIN-resultat för UPDATE med CTE
Använder CTE som grund för uppdatering av Enhetspris kolumnen är som att ha en tillfällig tabell först och sedan sammanfoga den tillfälliga tabellen till SalesOrderDetails . Vid första anblicken kan det se ut som att det inte är ett bra alternativ jämfört med de två första. Men det visar oss att det är möjligt att ha en uppdatering i MySQL med CTE. Det kan vara ett bra alternativ i andra situationer. Hur som helst, låt oss få EXPLAIN-resultaten för detta tillvägagångssätt.
Om du inte har dbForge Studio för MySQL kan du försöka skapa EXPLAIN-resultat med kommandot i vilken annan redigerare som helst. Här är ett exempel:
EXPLAIN
WITH priceIncrease AS
(
SELECT soh.SalesOrderID, p.ProductID, p.ListPrice
FROM `sales.salesorderdetail` sod
INNER JOIN `sales.salesorderheader` soh ON sod.SalesOrderID = soh.SalesOrderID
INNER JOIN `production.product` p ON sod.ProductID = p.ProductID
WHERE p.ProductID = 758
AND soh.OrderDate = '2012-04-30'
)
UPDATE `sales.salesorderdetail` s
INNER JOIN priceIncrease pi ON s.SalesOrderID = pi.SalesOrderID AND s.ProductID = pi.ProductID
SET s.UnitPrice = pi.ListPrice
Resultatet visas i figur 7 nedan.
Figur 7 visar:
- 4 tabeller användes istället för tre. Den första användningen av SalesOrderDetail finns i CTE och sedan i UPDATE-satsen.
- Fler tabeller betyder fler rader jämfört med de två tidigare metoderna.
Överraskande nog gick detta på 0,015 sekunder (visas inte i figuren). Detsamma är med att använda en underfråga. Det kommer dock inte att hända varje gång. Det beror på systemresurser som är tillgängliga vid tidpunkten för körning.
Den totala frågekostnaden är 166,69. Det är högre än de tidigare två tillvägagångssätten. Ju lägre frågekostnad, desto bättre prestanda över tid.
Hämtmat
Vi gjorde en djupdykning i skillnaderna mellan MySQL och SQL Servers UPDATE-sats. Vi har lärt oss hur det går till när du uppdaterar
- en enda kolumn
- flera kolumner
- tabeller med en join
- kolumner som använder en underfråga
- tabeller med en CTE
- med en LIMIT
I det här inlägget fick du också en smygtitt om EXPLAIN och hur man använder det för att jämföra olika UPDATE-metoder.
Jag hoppas att detta kan vara till hjälp för dig när du lär dig MySQL från SQL Server. Om du gillar det här inlägget, vänligen dela det på dina föredragna sociala medieplattformar. Och om något saknas, låt oss veta i kommentarsektionen.
Lycka till med kodningen!