Добавяте ли MySQL към вашия списък с набори от умения за база данни? Тогава MySQL UPDATE израз е една от командите, които трябва да научите.
Продължаваме нашето пътуване към MySQL от гледна точка на SQL Server. Започна със CREATE TABLE, последвано от INSERT, а най-новата част беше за DELETE. Днес UPDATE е нашата фокусна точка.
Разликите са фини и лесни за научаване. Но точно както в предишните статии, нашата цел е да ви накараме да работите бързо. Но преди да продължим, нека изясним тези елементи:
- Използваните тук примери се изпълняват на MySQL 8.0.23 с помощта на машината за съхранение InnoDB.
- Използвахме SQL Server 2019.
Подгответе примерните данни
Не можем да продължим без примерни данни. Бих искал да поставя разработчиците на T-SQL у дома в това упражнение. И така, нека импортираме някои познати таблици в AdventureWorks примерна база данни от SQL Server:
- Продукт
- SalesOrderHeader
- Подробности за SalesOrderDetails
За да импортирам тези таблици в MySQL, използвах dbForge Studio за MySQL. Ето стъпките:
- Създайте нова база данни, наречена adventureworks2019 .
- Щракнете с десния бутон върху adventureworks2019 и изберете Инструменти .
- Изберете Импортиране на данни . Ще се появи нов прозорец.
- Изберете ODBC . Трябва да създадете Потребителски DSN за да се свържете с вашия SQL Server и AdventureWorks база данни.
- Щракнете върху Напред .
- Изберете таблицата, която трябва да импортирате, връзката MySQL и целевата база данни (adventureworks2019 ).
- Щракнете върху Напред .
- Променете настройките на колоната. Можете също да видите примерни данни. Можете да пропуснете това, като щракнете върху Напред или променете настройките, както сметнете за добре.
- Щракнете върху Импортиране .
- Импортирайте следващата таблица, като следвате същите инструкции на екрана.
- Щракнете върху Край .
След като импортирате тези таблици, вече сте готови за примерите в тази статия. И така, да започнем.
1. Основи на синтаксиса
Синтаксисът на израза UPDATE на MySQL е следният:
UPDATE [LOW_PRIORITY] [IGNORE] table_references
SET assignment_list
[WHERE where_condition]
[ORDER BY ...]
[LIMIT row_count]
Почти мога да ви чуя, след като прочетох синтаксиса:НИСЪК ПРИОРИТЕТ, ИГНОРИРАЙТЕ, ПОРЪЧАЙТЕ ПО и LIMIT не пасват! Нека започнем да обсъждаме отгоре.
Първо, LOW_PRIORITY е чужда ключова дума за нас, защото SQL Server не я поддържа. Не е задължително, но ако го включите, актуализациите се забавят, докато всички други клиенти не четат таблицата.
Друга извънземна ключова дума е ИГНОРИРАНЕ. Също така е по избор, но ако го включите и се появят дубликати, няма да се изведе грешка. За повече игнорирани грешки вижте тази връзка.
След това ПОРЪЧАЙТЕ ОТ. Знаем за какво е. Но опитайте в SQL Server Management Studio и под ключовите думи ще се появят криволичещи линии.
И накрая, LIMIT. Това е същото като TOP в SQL Server. Повече за това и ПОРЪЧАЙТЕ В по-късен раздел.
Това са очевидните разлики. Прочетете повече в следващите 2 подраздела.
Една колона АКТУАЛИЗИРАНЕ на MySQL
Актуализирането на една колона е почти подобно. Така че примерът по-долу ще даде същия резултат от двете платформи на база данни. Обърнете внимание обаче, че вместо обратни отметки, SQL Server използва квадратни скоби.
-- MySQL UPDATE single column
UPDATE `production.product`
SET ReorderPoint = 650
WHERE ProductID = 316;
Ето еквивалентен синтаксис на T-SQL:
-- T-SQL UPDATE single column
UPDATE [Production].[Product]
SET ReorderPoint = 650
WHERE ProductID = 316;
Стойността, присвоена на колона, може да бъде произволен израз с една стойност, стига върнатият тип да е същият като типа данни на колоната.
MySQL АКТУАЛИЗАЦИЯ Множество колони
Актуализирането на множество колони също е почти подобно на T-SQL. Ето един пример:
UPDATE `production.product`
SET ReorderPoint = 650, SafetyStockLevel = 1200
WHERE ProductID = 316;
За да актуализирате няколко колони, просто отделете двойки колона-стойност със запетая. Отново, единствената разлика тук са тикчетата.
Досега това са всички актуализации на една таблица. Нека да преминем към MySQL UPDATE от друга таблица.
2. АКТУАЛИЗИРАНЕ на MySQL с JOIN
Има малки разлики, които ще видите, когато актуализирате таблица с обединения. Най-добрият начин да покажете това е чрез пример за използване на 3 таблици.
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';
Забележете, че някои клаузи са подредени по различен начин в сравнение със SQL Server. Съединенията се появяват първо преди клаузата SET. Няма и клауза FROM. Както можете да очаквате, SQL Server Management Studio ще постави криволичещи линии за синтаксиса на нарушението. Вижте това и правилния синтаксис на T-SQL на фигура 1 по-долу.
Преди актуализацията стойността на единичната цена е 874,7940, както се вижда на фигура 2.
След актуализацията UnitPrice се актуализира от Продукта ListPrice на таблицата . Вижте Фигура 3.
Освен INNER JOIN, можете да използвате LEFT или RIGHT JOIN в зависимост от вашите изисквания.
3. АКТУАЛИЗИРАНЕ на MySQL с подзаявка
Можете да използвате израза MySQL UPDATE от друга таблица, като използвате подзаявка. Заявката с присъединяване в предишния раздел може да бъде пренаписана с помощта на подзаявка. Резултатите ще бъдат същите. Ето го:
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';
Подходът е различен, но резултатът е същият като на фигура 3. Обърнете внимание обаче, че подзаявката, използвана за актуализиране на колона, трябва да върне 1 стойност.
Има и друг начин да се изрази този израз за MySQL UPDATE.
4. АКТУАЛИЗИРАНЕ на MySQL с CTE
Общите таблични изрази (CTE) се поддържат както в MySQL, така и в SQL Server. Ако не сте запознати с CTE, вижте предишната статия.
Сега, ето еквивалентното изявление с използван 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 поддържа същата концепция, но без обратни отметки. Резултатът ще бъде същият като на фигура 3.
Може да попитате кой от 3-те подхода е по-добър? Ще сравним тяхното представяне допълнително.
5. АКТУАЛИЗИРАНЕ на MySQL с LIMIT
MySQL UPDATE може да ограничи броя на редовете за актуализиране с ключовата дума LIMIT. Да предположим, че искаме да актуализираме 5 записа в Продукта маса. Можем да изразим твърдението по следния начин:
UPDATE `production.product` p
SET p.StandardCost = p.StandardCost + 10, p.ListPrice = p.ListPrice + 10
ORDER BY p.ProductID
LIMIT 5;
Това ще сортира записите въз основа на ProductID и след това актуализирайте първите 5 записа. Спира след 5-ия запис.
Двойникът на LIMIT на SQL Server е TOP. Въпреки това, не можете просто да промените ключовата дума LIMIT на TOP и да очаквате, че тя ще работи в SQL Server. Ето модифицираната версия в T-SQL, която ще даде същия резултат:
UPDATE Production.Product
SET StandardCost += 10, ListPrice += 10
WHERE ProductID IN (SELECT TOP 5 ProductID
FROM Production.Product
ORDER BY ProductID)
Логиката е малко по-различна. Той актуализира StandardCost и ListPrice колони въз основа на ProductID, намерени в подзаявката. Подзаявката, от друга страна, връща първите 5 записа на Продукта таблица, сортирана по ProductID .
Въпреки че TOP също се поддържа в T-SQL UPDATE, ORDER BY не. По този начин, използването на TOP с UPDATE ще промени произволните записи. Горният синтаксис е приложим за подредени записи с TOP.
Ефективност на актуализацията на MySQL
По-рано имахме оператор UPDATE със същите резултати, въпреки че използвахме различни методи. Използвахме JOIN, подзаявка и CTE. Кой от тях ще се представи най-добре?
Има и план за изпълнение в MySQL, използващ ключовата дума EXPLAIN. Синтаксисът е следният:
EXPLAIN [FORMAT=JSON]
<SQL statement>
Без формата JSON имате основна информация като таблици, използвани индексни ключове и сканирани редове. Когато е посочен формат JSON, имате по-подробна информация. dbForge Studio за MySQL включва Query Profiler в допълнение към резултата от EXPLAIN. MySQL Workbench включва Visual EXPLAIN, където можете да видите графичен изглед на плана въз основа на EXPLAIN FORMAT=JSON.
Сега, когато знаем операторите на командния ред и графичните инструменти, как можем да ги използваме за сравняване на различни методи?
Преди да продължим, нека бъда честен. Моите умения в SQL Server са по-високи, отколкото в MySQL. Може да пропусна нещо по пътя или да греша. Можете да попълните празнините в секцията Коментари по-късно.
Разбиране на резултати от EXPLAIN за UPDATE с JOIN
Първият път, когато изпълних оператора MySQL UPDATE с JOIN, отне 11,3 секунди за актуализиране на 24 реда. Невероятно, нали?
Ето какво се случи, както се вижда в dbForge Studio. Вижте фигура 4 по-долу.
Какво ни казва Фигура 4?
- Там са използвани 3 псевдонима на таблици. И 3те имат тип достъп ВСИЧКИ. Това означава, че MySQL използва сканиране на таблици за всички 3.
- Погледнете ключа колона. Нищо не се показва на всичките 3 таблици, което означава, че не са използвани индексни ключове. Това поддържа предишната точка от сканиране на таблица.
- Накрая, редовете колона. Той казва колко реда MySQL смята, че трябва да сканира, за да постигне крайния резултат. За актуализирани 24 реда, хиляди редове бяха сканирани за SalesOrderHeader и Подробности за SalesOrderDetails . Междувременно всички редове на Продукта таблицата бяха сканирани.
Почесах се по главата, когато научих това. Разбрах, че когато импортирах таблици от SQL Server, бяха импортирани само структурата на таблицата и данните, не индексите .
И така, създадох подходящи индекси и първични ключове в dbForge Studio. Ето какво създадох:
- Направих ProductID в Продукт таблица първичен ключ.
- Добавих и SalesOrderID като първичен ключ в SalesOrderHeader маса. След това направих индекс за OrderDate също.
- Накрая направих SalesOrderDetailID в SalesOrderDetail таблица първичен ключ. Добавих и индекс за SalesOrderID и ProductID колони на тази таблица.
След това генерирах нов план за изпълнение на същата заявка, за да видя подобренията. Резултатът?
УВЕЛИЧАВАНЕ НА СКОРОСТТА СЛЕД ДОБАВЯНЕ НА ИНДЕКСИТЕ
Времето за изпълнение е намалено от 11,3 секунди на 0,019 секунди. Много готино!
Нека проверим новия план с помощта на dbForge Studio на фигура 5 по-долу.
Какво ни казва Фигура 5?
- Достъпът видове от 3 таблици бяха променени. Двете стойности, които трябва да избягвате тук, са ALL и INDEX, особено при големи таблици. ALL е сканиране на таблица, а INDEX е индексно сканиране.
- Ключът колона сега включва използваните индекси. Това е добре. Използвани са всички добавени индекси.
- редовете колона сега показва по-малки цифри. Добавените индекси намалиха много I/O на нашата заявка.
За повече информация относно подробностите и стойностите на EXPLAIN вижте тази официална документация.
Но как се сравнява това с MySQL UPDATE с подзаявка?
Разбиране на резултати от EXPLAIN за UPDATE с подзаявка
Предишната заявка за актуализиране на UnitPrice колоната има друга алтернатива на заявка, която използва подзаявка. Как се сравнява с JOIN? Вижте фигура 6 по-долу.
Фигура 6 показва:
- Стойностите на колоните за тип, ключ и редове са еднакви в сравнение с използването на JOIN. Това е логично, тъй като трябва да има същите резултати.
- Времето за изпълнение отне малко по-бързо. Това обаче няма да се случва всеки път. Зависи от наличните ресурси в момента. Разликата в скоростта също е незначителна. Въобще няма да го усетите.
Друг начин е да използвате EXPLAIN FORMAT=JSON, за да получите повече информация за плана. При проверка стойностите на цената на заявката (84,79) и информацията за разходите са еднакви.
Сега нека го сравним с MySQL UPDATE с CTE.
Разбиране на резултати от EXPLAIN за UPDATE с CTE
Използване на CTE като основа за актуализиране на UnitPrice колоната е като първо да имате временна таблица и след това да присъедините временната таблица към SalesOrderDetails . На пръв поглед може да изглежда, че не е добър вариант в сравнение с първите два. Но това ни показва, че е възможно да имаме актуализация в MySQL, използвайки CTE. Може да бъде добър вариант в други ситуации. Както и да е, нека имаме резултатите EXPLAIN за този подход.
Ако нямате dbForge Studio за MySQL, можете да опитате да създадете резултати EXPLAIN, като използвате командата във всеки друг редактор. Ето един пример:
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
Резултатът е на фигура 7 по-долу.
Фигура 7 показва:
- 4 таблици бяха използвани вместо 3. Първото използване на SalesOrderDetail е в CTE и след това в изявлението UPDATE.
- Повече таблици означават повече редове в сравнение с предишните 2 подхода.
Изненадващо, това работи на 0,015 секунди (не е показано на фигурата). Същото е и с използването на подзаявка. Това обаче няма да се случва всеки път. Зависи от системните ресурси, налични към момента на изпълнение.
Общата цена на заявката е 166,69. Това е по-високо от предишните 2 подхода. Колкото по-ниска е цената на заявката, толкова по-добра е производителността във времето.
Вземане за вкъщи
Потопихме се дълбоко в разликите между MySQL и оператора UPDATE на SQL Server. Научихме как се прави при актуализиране
- единична колона
- много колони
- таблици с присъединяване
- колони, използващи подзаявка
- таблици с CTE
- с LIMIT
В тази публикация имахте кратък поглед върху EXPLAIN и как да го използвате, за да сравнявате различни подходи UPDATE.
Надявам се, че това може да ви бъде полезно, докато научавате MySQL, идващ от SQL Server. Ако ви харесва тази публикация, моля, споделете я в предпочитаните от вас социални медийни платформи. И ако нещо липсва, уведомете ни в секцията за коментари.
Приятно кодиране!