Přidáváte MySQL do svého seznamu databázových dovedností? Pak je příkaz MySQL UPDATE jedním z příkazů, které se musíte naučit.
Pokračujeme v naší cestě k MySQL z pohledu SQL Serveru. Začalo to CREATE TABLE, následovalo INSERT a poslední díl byl o DELETE. Dnes je UPDATE naším ústředním bodem.
Rozdíly jsou jemné a snadno se učí. Ale stejně jako v předchozích článcích je naším cílem, abyste byli rychle v provozu. Než však budeme pokračovat, ujasněme si tyto položky:
- Zde použité příklady byly spuštěny na MySQL 8.0.23 s využitím úložiště InnoDB.
- Použili jsme SQL Server 2019.
Připravte ukázková data
Bez ukázkových dat nemůžeme pokračovat. V tomto cvičení bych chtěl vývojáře T-SQL dát jako domov. Pojďme tedy importovat některé známé tabulky do AdventureWorks ukázková databáze ze serveru SQL:
- Produkt
- SalesOrderHeader
- Podrobnosti prodejní objednávky
K importu těchto tabulek do MySQL jsem použil dbForge Studio pro MySQL. Zde jsou kroky:
- Vytvořte novou databázi s názvem adventureworks2019 .
- Klikněte pravým tlačítkem na adventureworks2019 a vyberte Nástroje .
- Vyberte Importovat data . Zobrazí se nové okno.
- Vyberte ODBC . Musíte vytvořit Uživatelské DSN pro připojení k vašemu SQL Serveru a AdventureWorks databáze.
- Klikněte na tlačítko Další .
- Vyberte tabulku, kterou potřebujete importovat, připojení MySQL a cílovou databázi (adventureworks2019 ).
- Klikněte na tlačítko Další .
- Změňte nastavení sloupců. Můžete také vidět ukázková data. Toto můžete přeskočit kliknutím na Další nebo změňte nastavení, jak uznáte za vhodné.
- Klikněte na Importovat .
- Importujte další tabulku podle stejných pokynů na obrazovce.
- Klikněte na tlačítko Dokončit .
Po importu těchto tabulek jste nyní připraveni na příklady v tomto článku. Takže začněme.
1. Základy syntaxe
Syntaxe příkazu MySQL UPDATE vypadá takto:
UPDATE [LOW_PRIORITY] [IGNORE] table_references
SET assignment_list
[WHERE where_condition]
[ORDER BY ...]
[LIMIT row_count]
Po přečtení syntaxe vás skoro slyším:NÍZKÁ PRIORITA, IGNORACE, ORDER BY a LIMIT nesedí! Začněme diskutovat shora.
Za prvé, LOW_PRIORITY je pro nás cizí klíčové slovo, protože SQL Server ho nepodporuje. Je volitelná, ale pokud ji zahrnete, aktualizace se zdrží, dokud všichni ostatní klienti nebudou tabulku číst.
Dalším mimozemským klíčovým slovem je IGNORE. Je také volitelný, ale pokud jej zahrnete a dojde k duplikátům, chyba se nevyvolá. Další ignorovatelné chyby najdete na tomto odkazu.
Poté OBJEDNEJTE PODLE. Víme, k čemu to je. Ale zkuste to v SQL Server Management Studio a pod klíčovými slovy se objeví klikaté čáry.
Konečně LIMIT. To je stejné jako TOP v SQL Server. Více o tom a OBJEDNÁVKA v pozdější sekci.
To jsou zjevné rozdíly. Čtěte dále v následujících 2 podsekcích.
Aktualizace MySQL s jedním sloupcem
Aktualizace jednoho sloupce je téměř podobná. Níže uvedený příklad tedy poskytne stejný výsledek z obou databázových platforem. Všimněte si však, že místo zpětných zatržení používá SQL Server hranaté závorky.
-- MySQL UPDATE single column
UPDATE `production.product`
SET ReorderPoint = 650
WHERE ProductID = 316;
Zde je ekvivalentní syntaxe T-SQL:
-- T-SQL UPDATE single column
UPDATE [Production].[Product]
SET ReorderPoint = 650
WHERE ProductID = 316;
Hodnota přiřazená ke sloupci může být jakýkoli jednohodnotový výraz, pokud je vrácený typ stejný jako datový typ sloupce.
Aktualizace více sloupců MySQL
Aktualizace více sloupců je také téměř podobná T-SQL. Zde je příklad:
UPDATE `production.product`
SET ReorderPoint = 650, SafetyStockLevel = 1200
WHERE ProductID = 316;
Chcete-li aktualizovat více sloupců, jednoduše oddělte páry sloupec-hodnota čárkou. Opět platí, že jediným rozdílem je zde zpětné zatržení.
Zatím jsou to všechny aktualizace jedné tabulky. Přejděme k MySQL UPDATE z jiné tabulky.
2. AKTUALIZACE MySQL pomocí JOIN
Existují drobné rozdíly, které uvidíte při aktualizaci tabulky se spojeními. Nejlepší způsob, jak to ukázat, je na příkladu použití 3 tabulek.
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';
Všimněte si, že některé klauzule jsou ve srovnání se serverem SQL uspořádány odlišně. Spojení se objeví jako první před klauzulí SET. Není zde ani klauzule FROM. Jak můžete očekávat, SQL Server Management Studio vloží klikaté řádky pro problematickou syntaxi. Podívejte se na tuto a správnou syntaxi T-SQL na obrázku 1 níže.
Před aktualizací je hodnota jednotkové ceny 874,7940, jak je vidět na obrázku 2.
Po aktualizaci Jednotková cena je aktualizován z Produktu Cenová cena tabulky . Viz obrázek 3.
Kromě INNER JOIN můžete použít LEFT nebo RIGHT JOIN v závislosti na vašich požadavcích.
3. AKTUALIZACE MySQL pomocí poddotazu
Pomocí poddotazu můžete použít příkaz MySQL UPDATE z jiné tabulky. Dotaz se spojením v předchozí části lze přepsat pomocí poddotazu. Výsledky budou stejné. Tady:
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';
Přístup je odlišný, ale výsledek je stejný jako na obrázku 3. Pamatujte však, že poddotaz použitý k aktualizaci sloupce by měl vrátit hodnotu 1.
Existuje další způsob, jak vyjádřit tento příkaz MySQL UPDATE.
4. AKTUALIZACE MySQL pomocí CTE
Společné tabulkové výrazy (CTE) jsou podporovány v MySQL i SQL Server. Pokud CTE neznáte, podívejte se na předchozí článek.
Nyní je zde ekvivalentní prohlášení s použitým CTE.
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 podporuje stejný koncept, ale bez zpětných zaškrtnutí. Výsledek bude stejný jako na obrázku 3.
Můžete se zeptat, který ze 3 přístupů je lepší? Jejich výkon porovnáme dále.
5. AKTUALIZACE MySQL s LIMIT
MySQL UPDATE může omezit počet řádků k aktualizaci pomocí klíčového slova LIMIT. Předpokládejme, že chceme aktualizovat 5 záznamů v Produktu stůl. Výrok můžeme vyjádřit takto:
UPDATE `production.product` p
SET p.StandardCost = p.StandardCost + 10, p.ListPrice = p.ListPrice + 10
ORDER BY p.ProductID
LIMIT 5;
Tím se záznamy seřadí podle ID produktu a poté aktualizujte prvních 5 záznamů. Zastaví se po 5. záznamu.
Protějšek SQL Serveru LIMIT je TOP. Nemůžete však jen změnit klíčové slovo LIMIT na TOP a očekávat, že bude fungovat na SQL Serveru. Zde je upravená verze v T-SQL, která poskytne stejný výsledek:
UPDATE Production.Product
SET StandardCost += 10, ListPrice += 10
WHERE ProductID IN (SELECT TOP 5 ProductID
FROM Production.Product
ORDER BY ProductID)
Logika je trochu jiná. Aktualizuje StandardCost a Cenová cena sloupce na základě ProductID nalezených v poddotazu. Poddotaz na druhou stranu vrátí prvních 5 záznamů Produktu tabulka seřazená podle ID produktu .
Ačkoli TOP je také podporován v T-SQL UPDATE, ORDER BY nikoli. Použití TOP s UPDATE tedy změní náhodné záznamy. Výše uvedená syntaxe platí pro uspořádané záznamy s TOP.
Výkon AKTUALIZACE MySQL
Dříve jsme měli příkaz UPDATE se stejnými výsledky, i když jsme používali různé metody. Použili jsme JOIN, poddotaz a CTE. Který z nich bude mít nejlepší výkon?
V MySQL je také plán provádění pomocí klíčového slova EXPLAIN. Syntaxe je tato:
EXPLAIN [FORMAT=JSON]
<SQL statement>
Bez formátu JSON máte základní informace, jako jsou tabulky, použité indexové klíče a naskenované řádky. Když je zadán formát JSON, máte k dispozici podrobnější informace. dbForge Studio for MySQL obsahuje kromě výsledku EXPLAIN také Query Profiler. MySQL Workbench obsahuje Visual EXPLAIN, kde můžete vidět grafický pohled na plán založený na EXPLAIN FORMAT=JSON.
Nyní, když známe příkazy příkazového řádku a grafické nástroje, jak je můžeme použít k porovnání různých metod?
Než budeme pokračovat, dovolte mi být upřímný. Moje znalosti v SQL Serveru jsou vyšší než v MySQL. Možná mi cestou něco unikne nebo se mýlím. Mezery v sekci Komentáře můžete vyplnit později.
Rozbor výsledků EXPLAIN pro UPDATE pomocí JOIN
Když jsem poprvé spustil příkaz MySQL UPDATE s JOIN, trvalo 11,3 sekundy, než bylo aktualizováno 24 řádků. Neuvěřitelné, že?
Zde je to, co se stalo, jak je vidět v dbForge Studio. Podívejte se na obrázek 4 níže.
Co nám říká obrázek 4?
- Jsou zde použity 3 aliasy tabulek. Všechny 3 mají typy přístupu ALL. To znamená, že MySQL používá Table Scan pro všechny 3.
- Podívejte se na klíč sloupec. Ve všech 3 tabulkách se nic nezobrazuje, což znamená, že nebyly použity žádné indexové klíče. To podporuje předchozí bod prohledávání tabulky.
- Nakonec řádky sloupec. Říká, kolik řádků by podle MySQL mělo skenovat, aby bylo dosaženo konečného výsledku. U 24 aktualizovaných řádků byly naskenovány tisíce řádků pro SalesOrderHeader a SalesOrderDetails . Mezitím všechny řádky Produktu tabulka byla naskenována.
Když jsem se to dozvěděl, podrbal jsem se na hlavě. Uvědomil jsem si, že když jsem importoval tabulky ze serveru SQL, importovala se pouze struktura tabulky a data, ne indexy .
V dbForge Studio jsem tedy vytvořil příslušné indexy a primární klíče. Zde je to, co jsem vytvořil:
- Vytvořil jsem ID produktu v Produktu tabulka primární klíč.
- Přidal jsem také SalesOrderID jako primární klíč v SalesOrderHeader stůl. Poté jsem vytvořil index pro OrderDate taky.
- Nakonec jsem vytvořil SalesOrderDetailID v SalesOrderDetail tabulka primární klíč. Také jsem přidal index pro SalesOrderID a ID produktu sloupce této tabulky.
Poté jsem vygeneroval nový plán provádění pro stejný dotaz, abych viděl vylepšení. Výsledek?
ZVÝŠENÍ RYCHLOSTI PO PŘIDÁNÍ INDEXŮ
Doba provádění byla zkrácena z 11,3 sekundy na 0,019 sekundy. Velmi cool!
Podívejme se na nový plán pomocí dbForge Studio na obrázku 5 níže.
Co nám říká obrázek 5?
- Přístup typy 3 tabulky byly změněny. 2 hodnoty, kterým je třeba se vyhnout, jsou ALL a INDEX, zejména na velkých stolech. ALL je prohledávání tabulky a INDEX je prohledávání indexu.
- klíč sloupec nyní zahrnuje použité indexy. To je dobré. Byly použity všechny přidané indexy.
- řádky sloupec nyní ukazuje menší postavy. Přidané indexy snížily mnoho I/O na náš dotaz.
Další informace o podrobnostech a hodnotách EXPLAIN naleznete v této oficiální dokumentaci.
Ale jak je to ve srovnání s MySQL UPDATE s poddotazem?
Rozbor výsledků EXPLAIN pro UPDATE pomocí dílčího dotazu
Předchozí dotaz k aktualizaci Jednotkové ceny sloupec má jinou alternativu dotazu, která používá poddotaz. Jak se to srovnává s JOINem? Podívejte se na obrázek 6 níže.
Obrázek 6 ukazuje:
- Hodnoty sloupců typu, klíče a řádků jsou stejné jako při použití funkce JOIN. To je logické, protože by to mělo mít stejné výsledky.
- Doba provedení trvala o něco rychleji. To se však nestane pokaždé. Záleží na aktuálních dostupných zdrojích. Rozdíl v rychlosti je také zanedbatelný. Vůbec to neucítíte.
Dalším způsobem je použití EXPLAIN FORMAT=JSON k získání dalších informací o plánu. Po kontrole jsou hodnoty ceny dotazu (84,79) a informací o ceně stejné.
Nyní to porovnejme s MySQL UPDATE s CTE.
Rozbor výsledků EXPLAIN pro UPDATE pomocí CTE
Použití CTE jako základ pro aktualizaci Jednotkové ceny sloupec je jako mít nejprve dočasnou tabulku a poté dočasnou tabulku připojit k SalesOrderDetails . Na první pohled se může zdát, že to není dobrá volba ve srovnání s prvními dvěma. Ale ukazuje nám, že je možné mít aktualizaci v MySQL pomocí CTE. V jiných situacích to může být dobrá volba. Každopádně pojďme mít výsledky EXPLAIN pro tento přístup.
Pokud nemáte dbForge Studio pro MySQL, můžete zkusit vytvořit EXPLAIN výsledky pomocí příkazu v jakémkoli jiném editoru. Zde je příklad:
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
Výsledek je na obrázku 7 níže.
Obrázek 7 ukazuje:
- Byly použity 4 tabulky místo 3. První použití SalesOrderDetail je v CTE a poté v příkazu UPDATE.
- Více tabulek znamená více řádků ve srovnání se dvěma předchozími přístupy.
Překvapivě to běželo na 0,015 sekundy (na obrázku není znázorněno). To samé je s použitím poddotazu. Nestane se to však pokaždé. Závisí na systémových prostředcích, které jsou v době spuštění k dispozici.
Celková cena dotazu je 166,69. Je vyšší než předchozí 2 přístupy. Čím nižší jsou náklady na dotaz, tím lepší je výkon v průběhu času.
Takové věci
Hluboce jsme se ponořili do rozdílů mezi příkazem UPDATE MySQL a SQL Serveru. Naučili jsme se, jak se to dělá při aktualizaci
- jeden sloupec
- více sloupců
- tabulky se spojením
- sloupce pomocí dílčího dotazu
- tabulky s CTE
- s LIMITEM
V tomto příspěvku jste také nahlédli do EXPLAIN a jak jej použít k porovnání různých přístupů UPDATE.
Doufám, že vám to může být užitečné, když se naučíte MySQL pocházející ze serveru SQL. Pokud se vám tento příspěvek líbí, sdílejte jej na svých preferovaných platformách sociálních médií. A pokud něco chybí, dejte nám vědět v sekci Komentáře.
Hodně štěstí při kódování!