Mysql
 sql >> Datenbank >  >> RDS >> Mysql

MySQL-UPDATE:Top 5 Tipps für T-SQL-Entwickler

Fügen Sie MySQL zu Ihrer Liste der Datenbank-Skillsets hinzu? Dann ist die MySQL-UPDATE-Anweisung einer der Befehle, die Sie lernen müssen.

Wir setzen unsere Reise zu MySQL aus der Sicht von SQL Server fort. Es begann mit CREATE TABLE, gefolgt von INSERT, und das letzte Stück handelte von DELETE. Heute steht UPDATE im Mittelpunkt.

Die Unterschiede sind subtil und leicht zu erlernen. Aber genau wie in den vorherigen Artikeln ist es unser Ziel, Sie schnell zum Laufen zu bringen. Aber bevor wir fortfahren, lassen Sie uns diese Punkte klarstellen:

  • Die hier verwendeten Beispiele wurden auf MySQL 8.0.23 mit der InnoDB-Speicher-Engine ausgeführt.
  • Wir haben SQL Server 2019 verwendet.

Vorbereiten der Beispieldaten

Ohne Beispieldaten können wir nicht fortfahren. Ich möchte T-SQL-Entwickler in dieser Übung zu Hause lassen. Importieren wir also einige vertraute Tabellen in AdventureWorks Beispieldatenbank von SQL Server:

  • Produkt
  • SalesOrderHeader
  • SalesOrderDetails

Um diese Tabellen in MySQL zu importieren, habe ich dbForge Studio für MySQL verwendet. Hier sind die Schritte:

  1. Erstellen Sie eine neue Datenbank namens adventureworks2019 .
  2. Klicken Sie mit der rechten Maustaste auf adventureworks2019 und wählen Sie Tools aus .
  3. Wählen Sie Daten importieren . Ein neues Fenster wird angezeigt.
  4. Wählen Sie ODBC . Sie müssen einen Benutzer-DSN erstellen um sich mit Ihrem SQL Server und AdventureWorks zu verbinden Datenbank.
  5. Klicken Sie auf Weiter .
  6. Wählen Sie die zu importierende Tabelle, die MySQL-Verbindung und die Zieldatenbank (adventureworks2019 ).
  7. Klicken Sie auf Weiter .
  8. Ändern Sie die Spalteneinstellungen. Sie können auch Beispieldaten sehen. Sie können dies überspringen, indem Sie auf Weiter klicken oder ändern Sie die Einstellungen nach Belieben.
  9. Klicken Sie auf Importieren .
  10. Importieren Sie die nächste Tabelle, indem Sie denselben Anweisungen auf dem Bildschirm folgen.
  11. Klicken Sie auf Fertig stellen .

Nachdem Sie diese Tabellen importiert haben, sind Sie nun bereit für die Beispiele in diesem Artikel. Fangen wir also an.

1. Syntaxgrundlagen

Die Syntax der MySQL-UPDATE-Anweisung sieht folgendermaßen aus:

UPDATE [LOW_PRIORITY] [IGNORE] table_references
    SET assignment_list
    [WHERE where_condition]
    [ORDER BY ...]
    [LIMIT row_count]

Ich kann Sie fast hören, nachdem ich die Syntax gelesen habe:LOW PRIORITY, IGNORE, ORDER BY und LIMIT passen nicht! Beginnen wir mit der Diskussion ganz oben.

Erstens ist LOW_PRIORITY für uns ein fremdes Schlüsselwort, weil SQL Server es nicht unterstützt. Es ist optional, aber wenn Sie es einschließen, werden Aktualisierungen verzögert, bis alle anderen Clients die Tabelle nicht mehr lesen.

Ein weiteres Alien-Schlüsselwort ist IGNORE. Es ist auch optional, aber wenn Sie es einschließen und Duplikate auftreten, wird kein Fehler ausgelöst. Weitere ignorierbare Fehler finden Sie unter diesem Link.

Dann ORDER BY. Wir wissen, wofür es ist. Aber versuchen Sie es in SQL Server Management Studio und unter den Schlüsselwörtern erscheinen verschnörkelte Linien.

Endlich BEGRENZUNG. Dies ist dasselbe wie TOP in SQL Server. Mehr davon und ORDER BY in einem späteren Abschnitt.

Das sind die offensichtlichen Unterschiede. Lesen Sie weiter in den nächsten 2 Unterabschnitten.

MySQL UPDATE Einzelspalte

Das Aktualisieren einer einzelnen Spalte ist fast ähnlich. Das folgende Beispiel wird also auf beiden Datenbankplattformen dasselbe Ergebnis liefern. Beachten Sie jedoch, dass SQL Server anstelle von Backticks eckige Klammern verwendet.

-- MySQL UPDATE single column
UPDATE `production.product`
SET ReorderPoint = 650
WHERE ProductID = 316;

Hier ist eine äquivalente T-SQL-Syntax:

-- T-SQL UPDATE single column
UPDATE [Production].[Product]
SET ReorderPoint = 650
WHERE ProductID = 316;

Der einer Spalte zugewiesene Wert kann ein beliebiger Einzelwertausdruck sein, solange der zurückgegebene Typ mit dem Datentyp der Spalte übereinstimmt.

MySQL UPDATE Mehrere Spalten

Das Aktualisieren mehrerer Spalten ist auch T-SQL fast ähnlich. Hier ist ein Beispiel:

UPDATE `production.product`
SET ReorderPoint = 650, SafetyStockLevel = 1200
WHERE ProductID = 316;

Um mehrere Spalten zu aktualisieren, trennen Sie Spalten-Wert-Paare einfach durch ein Komma. Auch hier besteht der einzige Unterschied in den Backticks.

Bisher sind dies alles einzelne Tabellenaktualisierungen. Gehen wir von einer anderen Tabelle aus zu MySQL UPDATE über.

2. MySQL-UPDATE mit JOIN

Beim Aktualisieren einer Tabelle mit Joins werden Sie geringfügige Unterschiede feststellen. Am besten lässt sich dies anhand eines Beispiels mit 3 Tabellen zeigen.

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';

Beachten Sie, dass einige Klauseln im Vergleich zu SQL Server anders angeordnet sind. Joins erscheinen zuerst vor der SET-Klausel. Es gibt auch keine FROM-Klausel. Wie zu erwarten ist, fügt SQL Server Management Studio verschnörkelte Zeilen für die anstößige Syntax ein. Siehe dies und die korrekte T-SQL-Syntax in Abbildung 1 unten.

Vor der Aktualisierung beträgt der Stückpreiswert 874,7940, wie in Abbildung 2 zu sehen.

Nach dem Update UnitPrice wird vom Produkt aktualisiert ListPrice der Tabelle . Siehe Abbildung 3.

Abgesehen von INNER JOIN können Sie LEFT oder RIGHT JOIN je nach Ihren Anforderungen verwenden.

3. MySQL-UPDATE mit Unterabfrage

Sie können die MySQL UPDATE-Anweisung aus einer anderen Tabelle mit einer Unterabfrage verwenden. Die Abfrage mit einem Join im vorherigen Abschnitt kann mithilfe einer Unterabfrage neu geschrieben werden. Die Ergebnisse werden die gleichen sein. Hier geht's:

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';

Der Ansatz ist anders, aber das Ergebnis ist dasselbe wie in Abbildung 3. Beachten Sie jedoch, dass die zum Aktualisieren einer Spalte verwendete Unterabfrage 1 Wert zurückgeben sollte.

Es gibt eine andere Möglichkeit, diese MySQL-UPDATE-Anweisung auszudrücken.

4. MySQL-UPDATE mit CTE

Common Table Expressions (CTE) werden sowohl in MySQL als auch in SQL Server unterstützt. Wenn Sie mit CTEs nicht vertraut sind, sehen Sie sich den vorherigen Artikel an.

Nun, hier ist die äquivalente Anweisung mit CTE verwendet.

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 unterstützt dasselbe Konzept, jedoch ohne Backticks. Das Ergebnis ist dasselbe wie in Abbildung 3.

Sie fragen sich vielleicht, welcher der 3 Ansätze besser ist? Wir werden ihre Leistung weiter vergleichen.

5. MySQL-UPDATE mit LIMIT

MySQL UPDATE kann die Anzahl der zu aktualisierenden Zeilen mit dem Schlüsselwort LIMIT begrenzen. Angenommen, wir möchten 5 Datensätze im Produkt aktualisieren Tisch. Wir können die Aussage so ausdrücken:

UPDATE `production.product` p
SET p.StandardCost = p.StandardCost + 10, p.ListPrice = p.ListPrice + 10
ORDER BY p.ProductID
LIMIT 5;

Dadurch werden die Datensätze basierend auf ProductID sortiert , und aktualisieren Sie dann die ersten 5 Datensätze. Es stoppt nach dem 5. Datensatz.

Das Gegenstück des SQL Servers zu LIMIT ist TOP. Sie können das Schlüsselwort LIMIT jedoch nicht einfach in TOP ändern und erwarten, dass es in SQL Server funktioniert. Hier ist die modifizierte Version in T-SQL, die dasselbe Ergebnis liefert:

UPDATE Production.Product
SET StandardCost += 10, ListPrice += 10
WHERE ProductID IN (SELECT TOP 5 ProductID 
		    FROM Production.Product 
		    ORDER BY ProductID)

Die Logik ist etwas anders. Es aktualisiert StandardCost und Listenpreis Spalten basierend auf den in der Unterabfrage gefundenen ProductIDs. Die Unterabfrage hingegen gibt die ersten 5 Datensätze des Produkts zurück Tabelle sortiert nach ProductID .

Obwohl TOP auch in T-SQL UPDATE unterstützt wird, ist ORDER BY nicht. Daher wird die Verwendung von TOP mit UPDATE zufällige Datensätze ändern. Die obige Syntax gilt für geordnete Datensätze mit TOP.

MySQL-UPDATE-Leistung

Früher hatten wir eine UPDATE-Anweisung mit denselben Ergebnissen, obwohl wir unterschiedliche Methoden verwendet haben. Wir haben einen JOIN, eine Unterabfrage und einen CTE verwendet. Welcher von ihnen wird am besten abschneiden?

Es gibt auch einen Ausführungsplan in MySQL, der das Schlüsselwort EXPLAIN verwendet. Die Syntax ist wie folgt:

EXPLAIN [FORMAT=JSON]
<SQL statement>

Ohne das JSON-Format haben Sie grundlegende Informationen wie Tabellen, verwendete Indexschlüssel und gescannte Zeilen. Wenn das JSON-Format angegeben ist, erhalten Sie detailliertere Informationen. dbForge Studio for MySQL enthält zusätzlich zum Ergebnis von EXPLAIN einen Query Profiler. MySQL Workbench enthält ein visuelles EXPLAIN, in dem Sie eine grafische Ansicht des Plans basierend auf EXPLAIN FORMAT=JSON sehen können.

Nun, da wir die Befehlszeilenanweisungen und grafischen Tools kennen, wie können wir sie verwenden, um verschiedene Methoden zu vergleichen?

Lassen Sie mich ehrlich sein, bevor wir fortfahren. Meine Kenntnisse in SQL Server sind höher als in MySQL. Ich kann unterwegs etwas übersehen oder mich irren. Sie können die Lücken später im Kommentarbereich füllen.

Darstellung der EXPLAIN-Ergebnisse für UPDATE mit JOIN

Als ich das erste Mal die MySQL-UPDATE-Anweisung mit JOIN ausgeführt habe, dauerte es 11,3 Sekunden, bis 24 Zeilen aktualisiert wurden. Unglaublich, oder?

Folgendes ist in dbForge Studio passiert. Sehen Sie sich Abbildung 4 unten an.

Was sagt uns Abbildung 4?

  1. Die 3 verwendeten Tabellenaliase sind da. Alle 3 haben Zugriffstypen von ALL. Es bedeutet, dass MySQL Table Scan für alle 3 verwendet hat.
  2. Sehen Sie sich den Schlüssel an Säule. In allen 3 Tabellen wird nichts angezeigt, was bedeutet, dass keine Indexschlüssel verwendet wurden. Dies unterstützt den vorherigen Punkt von Table Scan.
  3. Schließlich die Reihen Säule. Es gibt an, wie viele Zeilen MySQL seiner Meinung nach scannen sollte, um das Endergebnis zu erzielen. Bei 24 aktualisierten Zeilen wurden Tausende von Zeilen nach SalesOrderHeader durchsucht und SalesOrderDetails . In der Zwischenzeit alle Zeilen des Produkts Tabelle gescannt.

Ich kratzte mich am Kopf, als ich das erfuhr. Mir ist aufgefallen, dass beim Importieren von Tabellen aus SQL Server nur die Tabellenstruktur und die Daten importiert wurden, nicht die Indizes .

Also habe ich in dbForge Studio entsprechende Indizes und Primärschlüssel erstellt. Folgendes habe ich erstellt:

  • Ich habe die ProductID erstellt im Produkt Tabelle einen Primärschlüssel.
  • Ich habe auch SalesOrderID hinzugefügt als Primärschlüssel im SalesOrderHeader Tisch. Dann habe ich einen Index für OrderDate erstellt auch.
  • Schließlich habe ich SalesOrderDetailID erstellt im SalesOrderDetail Tabelle einen Primärschlüssel. Ich habe auch einen Index für die SalesOrderID hinzugefügt und Produkt-ID Spalten dieser Tabelle.

Danach habe ich einen neuen Ausführungsplan für dieselbe Abfrage generiert, um die Verbesserungen zu sehen. Das Ergebnis?

GESCHWINDIGKEITSBOOST NACH DEM HINZUFÜGEN VON INDIZES

Die Ausführungszeit wurde von 11,3 Sekunden auf 0,019 Sekunden reduziert. Sehr cool!

Lassen Sie uns den neuen Plan mit dbForge Studio in Abbildung 5 unten überprüfen.

Was sagt uns Abbildung 5?

  • Der Zugriff Typen von 3 Tischen wurden geändert. Die beiden Werte, die Sie hier vermeiden sollten, sind ALL und INDEX, insbesondere bei großen Tabellen. ALL ist Table Scan und INDEX ist Index Scan.
  • Der Schlüssel Spalte enthält jetzt die verwendeten Indizes. Das ist gut. Alle hinzugefügten Indizes wurden verwendet.
  • Die Reihen Spalte zeigt jetzt kleinere Figuren. Die hinzugefügten Indizes reduzierten viele E/A-Vorgänge bei unserer Abfrage.

Weitere Informationen zu den EXPLAIN-Details und -Werten finden Sie in dieser offiziellen Dokumentation.

Aber wie ist das im Vergleich zu MySQL UPDATE mit Unterabfrage?

Erklären von EXPLAIN-Ergebnissen für UPDATE mit Unterabfrage

Die vorherige Abfrage zum Aktualisieren von UnitPrice Spalte hat eine andere Abfragealternative, die eine Unterabfrage verwendet. Wie ist es im Vergleich zum JOIN? Schauen Sie sich Abbildung 6 unten an.

Abbildung 6 zeigt:

  • Typ-, Schlüssel- und Zeilenspaltenwerte sind im Vergleich zur Verwendung von JOIN dieselben. Dies ist logisch, da es die gleichen Ergebnisse haben sollte.
  • Die Ausführung dauerte etwas schneller. Dies wird jedoch nicht jedes Mal passieren. Es hängt von den aktuell verfügbaren Ressourcen ab. Auch der Geschwindigkeitsunterschied ist vernachlässigbar. Du wirst es überhaupt nicht spüren.

Eine andere Möglichkeit ist die Verwendung von EXPLAIN FORMAT=JSON, um weitere Informationen über den Plan zu erhalten. Bei der Überprüfung sind die Werte für die Abfragekosten (84,79) und die Kosteninformationen identisch.

Vergleichen wir es jetzt mit MySQL UPDATE mit CTE.

Darstellung der EXPLAIN-Ergebnisse für UPDATE mit CTE

Verwenden von CTE als Grundlage für die Aktualisierung des UnitPrice -Spalte ist wie zuerst eine temporäre Tabelle zu haben und dann die temporäre Tabelle mit SalesOrderDetails zu verknüpfen . Auf den ersten Blick mag es so aussehen, als wäre es keine gute Option im Vergleich zu den ersten beiden. Aber es zeigt uns, dass es möglich ist, MySQL mit CTE zu aktualisieren. Es kann eine gute Option in anderen Situationen sein. Wie auch immer, lassen Sie uns die EXPLAIN-Ergebnisse für diesen Ansatz haben.

Wenn Sie dbForge Studio for MySQL nicht haben, können Sie versuchen, EXPLAIN-Ergebnisse mit dem Befehl in einem anderen Editor zu erzeugen. Hier ist ein Beispiel:

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

Das Ergebnis ist in Abbildung 7 unten zu sehen.

Abbildung 7 zeigt:

  • 4 statt 3 Tabellen wurden verwendet. Die erste Verwendung von SalesOrderDetail ist in der CTE und dann in der UPDATE-Anweisung.
  • Mehr Tabellen bedeuten mehr Zeilen im Vergleich zu den beiden vorherigen Ansätzen.

Überraschenderweise lief dieser bei 0,015 Sekunden (in der Figur nicht gezeigt). Dasselbe gilt für die Verwendung einer Unterabfrage. Es wird jedoch nicht jedes Mal passieren. Dies hängt von den zum Zeitpunkt der Ausführung verfügbaren Systemressourcen ab.

Die gesamten Abfragekosten betragen 166,69. Es ist höher als die vorherigen 2 Ansätze. Je niedriger die Abfragekosten, desto besser die Leistung im Laufe der Zeit.

Imbiss

Wir haben uns eingehend mit den Unterschieden zwischen der UPDATE-Anweisung von MySQL und SQL Server befasst. Wir haben gelernt, wie es beim Aktualisieren geht

  • eine einzelne Spalte
  • mehrere Spalten
  • Tabellen mit einem Join
  • Spalten, die eine Unterabfrage verwenden
  • Tabellen mit einem CTE
  • mit einem LIMIT

In diesem Beitrag hatten Sie auch einen kleinen Einblick in EXPLAIN und wie man damit verschiedene UPDATE-Ansätze vergleicht.

Ich hoffe, dass dies hilfreich für Sie sein kann, wenn Sie lernen, wie MySQL von SQL Server kommt. Wenn Ihnen dieser Beitrag gefällt, teilen Sie ihn bitte auf Ihren bevorzugten Social-Media-Plattformen. Und wenn etwas fehlt, lassen Sie es uns im Kommentarbereich wissen.

Viel Spaß beim Programmieren!