Czy dodajesz MySQL do swojej listy umiejętności baz danych? W takim razie instrukcja MySQL UPDATE jest jednym z poleceń, których musisz się nauczyć.
Kontynuujemy naszą podróż do MySQL z punktu widzenia SQL Server. Zaczęło się od CREATE TABLE, po czym nastąpiło INSERT, a najnowszy artykuł dotyczył DELETE. Dzisiaj UPDATE jest naszym głównym punktem.
Różnice są subtelne i łatwe do nauczenia. Ale tak jak w poprzednich artykułach, naszym celem jest, abyś szybko działał. Ale zanim przejdziemy dalej, wyjaśnijmy te kwestie:
- Przykłady użyte tutaj zostały uruchomione na MySQL 8.0.23 przy użyciu silnika pamięci masowej InnoDB.
- Użyliśmy SQL Server 2019.
Przygotuj przykładowe dane
Nie możemy kontynuować bez przykładowych danych. W tym ćwiczeniu chciałbym umieścić programistów T-SQL w domu. Zaimportujmy więc kilka znajomych tabel do AdventureWorks przykładowa baza danych z serwera SQL:
- Produkt
- Nagłówek zamówienia sprzedaży
- Szczegóły zamówienia sprzedaży
Aby zaimportować te tabele do MySQL, użyłem dbForge Studio for MySQL. Oto kroki:
- Utwórz nową bazę danych o nazwie adventureworks2019 .
- Kliknij prawym przyciskiem myszy adventureworks2019 i wybierz Narzędzia .
- Wybierz Importuj dane . Pojawi się nowe okno.
- Wybierz ODBC . Musisz utworzyć DSN użytkownika aby połączyć się z serwerem SQL i AdventureWorks baza danych.
- Kliknij Dalej .
- Wybierz tabelę, którą chcesz zaimportować, połączenie MySQL i docelową bazę danych (adventureworks2019 ).
- Kliknij Dalej .
- Zmień ustawienia kolumny. Możesz również zobaczyć przykładowe dane. Możesz to pominąć, klikając Dalej lub zmień ustawienia według własnego uznania.
- Kliknij Importuj .
- Zaimportuj następną tabelę, postępując zgodnie z tymi samymi instrukcjami wyświetlanymi na ekranie.
- Kliknij Zakończ .
Po zaimportowaniu tych tabel możesz teraz zapoznać się z przykładami w tym artykule. Więc zacznijmy.
1. Podstawy składni
Składnia instrukcji MySQL UPDATE wygląda następująco:
UPDATE [LOW_PRIORITY] [IGNORE] table_references
SET assignment_list
[WHERE where_condition]
[ORDER BY ...]
[LIMIT row_count]
Prawie cię słyszę po przeczytaniu składni:NISKI PRIORYTET, IGNORUJ, ZAMÓW BY i LIMIT nie pasują! Zacznijmy dyskusję od góry.
Po pierwsze, LOW_PRIORITY jest dla nas obcym słowem kluczowym, ponieważ SQL Server go nie obsługuje. Jest to opcjonalne, ale jeśli go uwzględnisz, aktualizacje są opóźnione, dopóki wszyscy inni klienci nie będą czytać tabeli.
Innym słowem kluczowym obcych jest IGNORE. Jest to również opcjonalne, ale jeśli je uwzględnisz i wystąpią duplikaty, błąd nie zostanie zgłoszony. Więcej błędów, które można zignorować, znajdziesz pod tym linkiem.
Następnie ZAMÓW PRZEZ. Wiemy, do czego to służy. Ale wypróbuj to w SQL Server Management Studio, a faliste linie pojawią się pod słowami kluczowymi.
Wreszcie LIMIT. To to samo, co TOP w SQL Server. Więcej o tym i ORDER BY w dalszej części.
To są oczywiste różnice. Czytaj dalej w kolejnych 2 podrozdziałach.
Pojedyncza kolumna UPDATE MySQL
Aktualizacja pojedynczej kolumny jest prawie podobna. Tak więc poniższy przykład da ten sam wynik z obu platform baz danych. Należy jednak pamiętać, że zamiast znaków wstecznych SQL Server używa nawiasów kwadratowych.
-- MySQL UPDATE single column
UPDATE `production.product`
SET ReorderPoint = 650
WHERE ProductID = 316;
Oto odpowiednik składni T-SQL:
-- T-SQL UPDATE single column
UPDATE [Production].[Product]
SET ReorderPoint = 650
WHERE ProductID = 316;
Wartość przypisana do kolumny może być dowolnym wyrażeniem jednowartościowym, o ile zwracany typ jest taki sam jak typ danych kolumny.
MySQL UPDATE Wiele kolumn
Aktualizacja wielu kolumn jest również prawie podobna do T-SQL. Oto przykład:
UPDATE `production.product`
SET ReorderPoint = 650, SafetyStockLevel = 1200
WHERE ProductID = 316;
Aby zaktualizować wiele kolumn, po prostu oddziel pary kolumna-wartość przecinkiem. Znowu jedyną różnicą są backticki.
Jak dotąd są to wszystkie aktualizacje pojedynczych tabel. Przejdźmy do MySQL UPDATE z innej tabeli.
2. AKTUALIZACJA MySQL z JOIN
Istnieją niewielkie różnice, które zobaczysz podczas aktualizowania tabeli za pomocą złączeń. Najlepszym sposobem, aby to pokazać, jest przykład użycia 3 tabel.
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';
Zwróć uwagę, że niektóre klauzule są rozmieszczone inaczej niż w SQL Server. Sprzężenia pojawiają się jako pierwsze przed klauzulą SET. Nie ma też klauzuli FROM. Jak można się spodziewać, SQL Server Management Studio wstawia faliste linie dla nieprawidłowej składni. Zobacz to i poprawną składnię T-SQL na Rysunku 1 poniżej.
Przed aktualizacją cena jednostkowa wynosiła 874,7940, jak pokazano na rysunku 2.
Po aktualizacji Cena jednostkowa jest aktualizowany z Produktu ListPrice tabeli . Zobacz rysunek 3.
Oprócz INNER JOIN możesz użyć LEFT lub RIGHT JOIN w zależności od Twoich wymagań.
3. AKTUALIZACJA MySQL z podzapytaniem
Możesz użyć instrukcji MySQL UPDATE z innej tabeli za pomocą podzapytania. Zapytanie ze sprzężeniem w poprzedniej sekcji można przepisać za pomocą podzapytania. Wyniki będą takie same. Oto idzie:
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';
Podejście jest inne, ale wynik jest taki sam jak na rysunku 3. Należy jednak pamiętać, że podzapytanie użyte do aktualizacji kolumny powinno zwrócić 1 wartość.
Jest inny sposób wyrażenia tej instrukcji MySQL UPDATE.
4. AKTUALIZACJA MySQL z CTE
Common Table Expressions (CTE) są obsługiwane zarówno w MySQL, jak i SQL Server. Jeśli nie znasz CTE, zapoznaj się z poprzednim artykułem.
Oto równoważne stwierdzenie z użytym 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 obsługuje tę samą koncepcję, ale bez backticków. Wynik będzie taki sam jak na rysunku 3.
Możesz zapytać, które z 3 podejść jest lepsze? Będziemy dalej porównywać ich wydajność.
5. UPDATE MySQL z LIMIT
MySQL UPDATE może ograniczyć liczbę wierszy do aktualizacji za pomocą słowa kluczowego LIMIT. Załóżmy, że chcemy zaktualizować 5 rekordów w Produkcie stół. Stwierdzenie możemy wyrazić w ten sposób:
UPDATE `production.product` p
SET p.StandardCost = p.StandardCost + 10, p.ListPrice = p.ListPrice + 10
ORDER BY p.ProductID
LIMIT 5;
Spowoduje to posortowanie rekordów na podstawie ID produktu , a następnie zaktualizuj pierwsze 5 rekordów. Zatrzymuje się po piątym rekordzie.
Odpowiednikiem LIMIT w SQL Server jest TOP. Nie można jednak po prostu zmienić słowa kluczowego LIMIT na TOP i oczekiwać, że będzie ono działać w SQL Server. Oto zmodyfikowana wersja w T-SQL, która da ten sam wynik:
UPDATE Production.Product
SET StandardCost += 10, ListPrice += 10
WHERE ProductID IN (SELECT TOP 5 ProductID
FROM Production.Product
ORDER BY ProductID)
Logika jest nieco inna. Aktualizuje koszt standardowy i ListPrice kolumny oparte na identyfikatorach ProductID znalezionych w podzapytaniu. Z drugiej strony podzapytanie zwraca pierwszych 5 rekordów Produktu tabela posortowana według ID produktu .
Chociaż TOP jest również obsługiwany w T-SQL UPDATE, ORDER BY nie jest. Tak więc użycie TOP z UPDATE zmodyfikuje losowe rekordy. Powyższa składnia ma zastosowanie do uporządkowanych rekordów z TOP.
Wydajność aktualizacji MySQL
Wcześniej mieliśmy instrukcję UPDATE z tymi samymi wynikami, mimo że używaliśmy różnych metod. Użyliśmy JOIN, podzapytania i CTE. Który z nich będzie działał najlepiej?
Istnieje również plan wykonania w MySQL za pomocą słowa kluczowego EXPLAIN. Składnia jest taka:
EXPLAIN [FORMAT=JSON]
<SQL statement>
Bez formatu JSON masz podstawowe informacje, takie jak tabele, używane klucze indeksu i skanowane wiersze. Po określeniu formatu JSON masz bardziej szczegółowe informacje. dbForge Studio dla MySQL zawiera Query Profiler oprócz wyniku EXPLAIN. MySQL Workbench zawiera Visual EXPLAIN, w którym można zobaczyć graficzny widok planu oparty na EXPLAIN FORMAT=JSON.
Teraz, gdy znamy polecenia wiersza poleceń i narzędzia graficzne, jak możemy ich użyć do porównania różnych metod?
Zanim przejdziemy dalej, powiem szczerze. Moja biegłość w SQL Server jest wyższa niż w MySQL. Mogę coś przeoczyć po drodze lub się mylić. Możesz wypełnić luki w sekcji Komentarze później.
Przeanalizowanie wyników EXPLAIN dla UPDATE z JOIN
Kiedy pierwszy raz uruchomiłem instrukcję MySQL UPDATE z opcją JOIN, aktualizacja 24 wierszy zajęła 11,3 sekundy. Niewiarygodne, prawda?
Oto, co się stało, jak widać w dbForge Studio. Sprawdź Rysunek 4 poniżej.
Co mówi nam Rysunek 4?
- Są tam używane 3 aliasy tabel. Wszystkie 3 mają typy dostępu WSZYSTKIE. Oznacza to, że MySQL używał skanowania tabel dla wszystkich 3.
- Spójrz na klawisz kolumna. Nic nie jest wyświetlane we wszystkich 3 tabelach, co oznacza, że nie użyto żadnych kluczy indeksu. Obsługuje to poprzedni punkt skanowania tabeli.
- Na koniec wiersze kolumna. Mówi on, ile wierszy MySQL powinien przeskanować, aby osiągnąć ostateczny wynik. W przypadku zaktualizowanych 24 wierszy przeskanowano tysiące wierszy pod kątem SalesOrderHeader i Szczegóły zamówienia sprzedaży . Tymczasem wszystkie wiersze Produktu tabela została zeskanowana.
Podrapałem się w głowę, gdy się o tym dowiedziałem. Zdałem sobie sprawę, że kiedy importowałem tabele z SQL Server, importowano tylko strukturę tabeli i dane, nie indeksy .
Stworzyłem więc odpowiednie indeksy i klucze podstawowe w dbForge Studio. Oto, co stworzyłem:
- Utworzyłem ID produktu w Produkcie podaj klucz podstawowy.
- Dodałem również SalesOrderID jako klucz podstawowy w SalesOrderHeader stół. Następnie utworzyłem indeks dla OrderDate też.
- Na koniec utworzyłem SalesOrderDetailID w Szczegółach Zamówień Sprzedaży tabeli klucz podstawowy. Dodałem również indeks dla SalesOrderID i ID produktu kolumny tej tabeli.
Następnie wygenerowałem nowy plan wykonania dla tego samego zapytania, aby zobaczyć ulepszenia. Wynik?
ZWIĘKSZENIE PRĘDKOŚCI PO DODAWANIU INDEKSÓW
Czas wykonania został skrócony z 11,3 sekundy do 0,019 sekundy. Bardzo fajnie!
Sprawdźmy nowy plan za pomocą dbForge Studio na rysunku 5 poniżej.
Co mówi nam Rysunek 5?
- Dostęp typy 3 stoły zostały zmienione. Dwie wartości, których należy tutaj unikać, to ALL i INDEX, szczególnie w przypadku dużych tabel. ALL to skanowanie tabeli, a INDEX to skanowanie indeksu.
- Klucz kolumna teraz zawiera używane indeksy. To jest dobre. Wszystkie dodane indeksy zostały wykorzystane.
- Wiersze kolumna teraz pokazuje mniejsze liczby. Dodane indeksy zmniejszyły wiele operacji we/wy w naszym zapytaniu.
Aby uzyskać więcej informacji na temat szczegółów i wartości EXPLAIN, zapoznaj się z tą oficjalną dokumentacją.
Ale jak to się ma do MySQL UPDATE z podzapytaniem?
Przeanalizowanie wyników EXPLAIN dla UPDATE za pomocą podzapytania
Poprzednie zapytanie aktualizujące cenę jednostkową kolumna ma inną alternatywę zapytania, która używa podzapytania. Jak to się ma do JOIN? Sprawdź Rysunek 6 poniżej.
Rysunek 6 pokazuje:
- Wartości kolumn typu, klucza i wierszy są takie same, jak przy użyciu funkcji JOIN. Jest to logiczne, ponieważ powinno dawać takie same wyniki.
- Czas wykonania trwał nieco szybciej. Jednak nie za każdym razem tak się stanie. To zależy od aktualnych dostępnych zasobów. Różnica prędkości jest również znikoma. W ogóle tego nie poczujesz.
Innym sposobem jest użycie EXPLAIN FORMAT=JSON, aby uzyskać więcej informacji o planie. Po sprawdzeniu koszt zapytania (84,79) i informacje o kosztach są takie same.
Teraz porównajmy to z MySQL UPDATE z CTE.
Przeanalizowanie wyników EXPLAIN dla UPDATE z CTE
Używanie CTE jako podstawy do aktualizacji Ceny Jednostkowej kolumna jest jak posiadanie najpierw tabeli tymczasowej, a następnie dołączenie tabeli tymczasowej do SalesOrderDetails . Na pierwszy rzut oka może się wydawać, że nie jest to dobra opcja w porównaniu do dwóch pierwszych. Ale pokazuje nam, że można mieć aktualizację w MySQL za pomocą CTE. Może być dobrym rozwiązaniem w innych sytuacjach. W każdym razie miejmy wyniki WYJAŚNIJ dla tego podejścia.
Jeśli nie masz dbForge Studio dla MySQL, możesz spróbować wygenerować wyniki EXPLAIN za pomocą polecenia w dowolnym innym edytorze. Oto przykład:
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
Wynik przedstawiono na Rysunku 7 poniżej.
Rysunek 7 pokazuje:
- Użyto 4 tabel zamiast 3. Pierwsze użycie SalesOrderDetail znajduje się w CTE, a następnie w instrukcji UPDATE.
- Więcej tabel oznacza więcej wierszy w porównaniu z dwoma poprzednimi podejściami.
Co zaskakujące, trwało to 0,015 sekundy (nie pokazano na rysunku). To samo dotyczy użycia podzapytania. Jednak nie za każdym razem tak się stanie. Zależy to od zasobów systemowych dostępnych w czasie wykonywania.
Całkowity koszt zapytania to 166,69. Jest wyższy niż w poprzednich 2 podejściach. Im niższy koszt zapytania, tym lepsza wydajność w czasie.
Na wynos
Zagłębiliśmy się w różnice między instrukcją UPDATE w MySQL i SQL Server. Dowiedzieliśmy się, jak to się robi podczas aktualizacji
- pojedyncza kolumna
- wiele kolumn
- stoły z łączeniem
- kolumny używające podzapytania
- tabele z CTE
- z LIMIT
W tym poście miałeś również zajawkę na temat EXPLAIN i tego, jak go używać do porównywania różnych podejść do aktualizacji.
Mam nadzieję, że będzie to pomocne podczas nauki MySQL pochodzącego z SQL Server. Jeśli podoba Ci się ten post, udostępnij go na preferowanych platformach społecznościowych. A jeśli czegoś brakuje, daj nam znać w sekcji Komentarze.
Miłego kodowania!