sql >> データベース >  >> RDS >> Mysql

MySQL UPDATE:T-SQL開発者向けのトップ5のヒント

    データベーススキルセットのリストにMySQLを追加していますか?次に、MySQLUPDATEステートメントは学習する必要のあるコマンドの1つです。

    SQLServerの観点からMySQLへの旅を続けています。それはCREATETABLEで始まり、次にINSERTが続き、最新の部分はDELETEに関するものでした。今日、UPDATEが私たちの焦点です。

    違いは微妙で習得が容易です。しかし、前の記事と同じように、私たちの目標は、あなたを迅速に立ち上げて実行させることです。ただし、先に進む前に、次の項目を明確にしましょう。

    • ここで使用されている例は、InnoDBストレージエンジンを使用してMySQL8.0.23で実行されました。
    • SQLServer2019を使用しました。

    サンプルデータを準備する

    サンプルデータなしでは先に進めません。この演習では、T-SQL開発者を自宅に配置したいと思います。それでは、おなじみのテーブルを AdventureWorksにインポートしましょう。 SQL Serverのサンプルデータベース:

    • 製品
    • SalesOrderHeader
    • SalesOrderDetails

    これらのテーブルをMySQLにインポートするために、dbForge StudioforMySQLを使用しました。手順は次のとおりです。

    1. adventureworks2019という新しいデータベースを作成します 。
    2. adventureworks2019を右クリックします ツールを選択します 。
    3. データのインポートを選択します 。新しいウィンドウが表示されます。
    4. ODBCを選択します 。 ユーザーDSNを作成する必要があります SQLServerとAdventureWorksに接続します データベース。
    5. [次へ]をクリックします 。
    6. インポートする必要のあるテーブル、MySQL接続、およびターゲットデータベースを選択します( adventureworks2019
    7. [次へ]をクリックします 。
    8. 列の設定を変更します。サンプルデータもご覧いただけます。 次へをクリックすると、これをスキップできます または、必要に応じて設定を変更してください。
    9. [インポート]をクリックします 。
    10. 同じ画面の指示に従って、次のテーブルをインポートします。
    11. [完了]をクリックします 。

    これらのテーブルをインポートすると、この記事の例の準備が整います。それでは、始めましょう。

    1。構文の基本

    MySQLUPDATEステートメントの構文は次のようになります。

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

    構文を読んだ後、ほとんど聞こえます:LOW PRIORITY、IGNORE、ORDER BY、およびLIMITは適合しません!上から話し合いを始めましょう。

    まず、LOW_PRIORITYは、SQL Serverがサポートしていないため、私たちにとっては異質なキーワードです。これはオプションですが、これを含めると、他のすべてのクライアントがテーブルを読み取らなくなるまで更新が遅れます。

    もう1つのエイリアンキーワードはIGNOREです。これもオプションですが、これを含めて重複が発生した場合、エラーは発生しません。無視できるエラーについては、このリンクを確認してください。

    次に、ORDERBY。私たちはそれが何のためにあるかを知っています。ただし、SQL Server Management Studioで試してみると、キーワードの下に波線が表示されます。

    最後に、LIMIT。これは、SQLServerのTOPと同じです。これについては、後のセクションで詳しく説明します。

    これらは明らかな違いです。次の2つのサブセクションでさらに読んでください。

    MySQLUPDATE単一列

    単一の列の更新はほとんど同じです。したがって、以下の例では、両方のデータベースプラットフォームから同じ結果が生成されます。ただし、SQLServerはバッククォートの代わりに角かっこを使用することに注意してください。

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

    列に割り当てられる値は、返される型が列のデータ型と同じである限り、任意の単一値式にすることができます。

    MySQLUPDATEの複数の列

    複数の列の更新も、T-SQLとほぼ同じです。次に例を示します:

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

    複数の列を更新するには、列と値のペアをコンマで区切るだけです。繰り返しますが、ここでの唯一の違いはバックティックです。

    これまでのところ、これらはすべて単一テーブルの更新です。別のテーブルからMySQLUPDATEに移りましょう。

    2。 JOINを使用したMySQLUPDATE

    結合を使用してテーブルを更新するときに表示される小さな違いがあります。これを示す最良の方法は、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は、問題のある構文に波線を表示します。これと、下の図1の正しいT-SQL構文を参照してください。

    更新前の単価は、図2に示すように874.7940です。

    更新後、 UnitPrice 製品から更新されます テーブルのListPrice 。図3を参照してください。

    INNER JOINの他に、要件に応じてLEFTまたはRIGHTJOINを使用できます。

    3。サブクエリを使用したMySQLUPDATE

    サブクエリを使用して、別のテーブルのMySQLUPDATEステートメントを使用できます。前のセクションで結合されたクエリは、サブクエリを使用して書き直すことができます。結果は同じになります。

    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つの値を返す必要があることに注意してください。

    このMySQLUPDATEステートメントを表現する別の方法があります。

    4。 CTEを使用したMySQLUPDATE

    Common Table Expressions(CTE)は、MySQLとSQLServerの両方でサポートされています。 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。制限付きのMySQLUPDATE

    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番目のレコードの後で停止します。

    SQLServerのLIMITに対応するものはTOPです。ただし、LIMITキーワードをTOPに変更して、SQLServerで機能することを期待することはできません。同じ結果が得られる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-SQLUPDATEでもサポートされていますが、ORDERBYはサポートされていません。したがって、TOPをUPDATEとともに使用すると、ランダムレコードが変更されます。上記の構文は、TOPを使用した順序付きレコードに適用できます。

    MySQLUPDATEのパフォーマンス

    以前は、異なるメソッドを使用したにもかかわらず、同じ結果のUPDATEステートメントがありました。 JOIN、サブクエリ、およびCTEを使用しました。どれが最高のパフォーマンスを発揮しますか?

    EXPLAINキーワードを使用したMySQLの実行プランもあります。構文は次のようになります:

    EXPLAIN [FORMAT=JSON]
    <SQL statement>
    

    JSON形式がないと、テーブル、使用されるインデックスキー、スキャンされた行などの基本情報が得られます。 JSON形式を指定すると、より詳細な情報が得られます。 dbForge Studio for MySQLには、EXPLAINの結果に加えてクエリプロファイラーが含まれています。 MySQL Workbenchには、EXPLAIN FORMAT=JSONに基づいてプランのグラフィカルビューを表示できるビジュアルEXPLAINが含まれています。

    コマンドラインステートメントとグラフィカルツールがわかったので、それらを使用してさまざまなメソッドを比較するにはどうすればよいですか?

    先に進む前に、正直に言いましょう。私のSQLServerの習熟度は、MySQLよりも高くなっています。途中で何かを見逃したり、間違っている可能性があります。後でコメントセクションのギャップを埋めることができます。

    JOINを使用したUPDATEのEXPLAIN結果の分析

    JOINを使用してMySQLUPDATEステートメントを初めて実行したとき、24行が更新されるまでに11.3秒かかりました。信じられないですね。

    これがdbForgeStudioで見られるように起こったことです。下の図4を確認してください。

    図4から何がわかりますか?

    1. 使用される3つのテーブルエイリアスがあります。 3つすべてにALLのアクセスタイプがあります。これは、MySQLがすべての3にテーブルスキャンを使用したことを意味します。
    2. キーを見てください 桁。 3つのテーブルすべてに何も表示されません。つまり、インデックスキーは使用されませんでした。これは、テーブルスキャンの前のポイントをサポートします。
    3. 最後に、 桁。これは、MySQLが最終結果を達成するためにスキャンする必要があると信じている行数を示します。更新された24行について、数千行がスキャンされて SalesOrderHeader およびSalesOrderDetails 。一方、製品のすべての行 テーブルがスキャンされました。

    私はこれを知って頭をかいた。 SQL Serverからテーブルをインポートすると、テーブル構造とデータのみがインポートされ、インデックスはインポートされないことに気付きました。 。

    そこで、dbForgeStudioで適切なインデックスと主キーを作成しました。これが私が作成したものです:

    • ProductIDを作成しました 製品 主キーをテーブルします。
    • SalesOrderIDも追加しました SalesOrderHeaderの主キーとして テーブル。次に、 OrderDateのインデックスを作成しました
    • 最後に、 SalesOrderDetailIDを作成しました SalesOrderDetail テーブルの主キー。 SalesOrderIDのインデックスも追加しました およびProductID このテーブルの列。

    この後、同じクエリの新しい実行プランを生成して、改善点を確認しました。結果は?

    インデックス追加後のスピードブースト

    実行時間が11.3秒から0.019秒に短縮されました。とてもかっこいい!

    下の図5のdbForgeStudioを使用して新しい計画を確認しましょう。

    図5から何がわかりますか?

    • アクセス タイプ 3つのテーブルのうちが変更されました。ここで避けるべき2つの値は、特に大きなテーブルではALLとINDEXです。 ALLはテーブルスキャンで、INDEXはインデックススキャンです。
    • キー 使用されるインデックスが含まれるようになりました。これはいい。追加されたすべてのインデックスが使用されました。
    • 小さい数字が表示されるようになりました。追加されたインデックスにより、クエリのI/Oが大幅に削減されました。

    EXPLAINの詳細と値の詳細については、この公式ドキュメントを確認してください。

    しかし、これはサブクエリを使用したMySQL UPDATEとどのように比較されますか?

    サブクエリを使用したUPDATEのEXPLAIN結果の分析

    UnitPriceを更新するための前のクエリ 列には、サブクエリを使用する別のクエリの選択肢があります。 JOINと比べてどうですか?下の図6を確認してください。

    図6は次のことを示しています:

    • タイプ、キー、および行の列の値は、JOINを使用する場合と同じです。同じ結果になるはずなので、これは論理的です。
    • 実行時間は少し速くなりました。ただし、これは毎回発生するわけではありません。これは、現在利用可能なリソースによって異なります。速度差もごくわずかです。まったく感じません。

    もう1つの方法は、EXPLAIN FORMAT =JSONを使用して、プランに関する詳細情報を取得することです。チェックすると、クエリコスト(84.79)とコスト情報の値は同じです。

    それでは、CTEを使用したMySQLUPDATEと比較してみましょう。

    CTEを使用したUPDATEのEXPLAIN結果の分析

    UnitPriceを更新するための基礎としてCTEを使用する 列は、最初に一時テーブルを作成してから、一時テーブルを SalesOrderDetailsに結合するようなものです。 。一見すると、最初の2つと比較して適切なオプションではないように見えるかもしれません。しかし、CTEを使用してMySQLで更新を行うことが可能であることを示しています。他の状況では良いオプションになる可能性があります。とにかく、このアプローチのEXPLAINの結果を見てみましょう。

    dbForge Studio for 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は次のことを示しています:

    • 3つではなく4つのテーブルが使用されました。SalesOrderDetailの最初の使用 CTEにあり、次にUPDATEステートメントにあります。
    • 以前の2つのアプローチと比較して、テーブルが多いほど行が多くなります。

    驚いたことに、これは0.015秒で実行されました(図には示されていません)。サブクエリを使用する場合も同様です。ただし、毎回発生するわけではありません。実行時に利用可能なシステムリソースによって異なります。

    クエリの総コストは166.69です。前の2つのアプローチよりも高くなっています。クエリコストが低いほど、長期的なパフォーマンスが向上します。

    要点

    MySQLとSQLServerのUPDATEステートメントの違いを深く掘り下げました。更新時にどのように行われるかを学びました

    • 単一の列
    • 複数の列
    • 結合のあるテーブル
    • サブクエリを使用する列
    • CTEのあるテーブル
    • 制限付き

    この投稿では、EXPLAINと、それを使用してさまざまなUPDATEアプローチを比較する方法についても簡単に説明しました。

    SQL ServerからMySQLを学ぶときに、これがお役に立てば幸いです。この投稿が気に入ったら、お好みのソーシャルメディアプラットフォームで共有してください。また、不足しているものがある場合は、コメントセクションでお知らせください。

    ハッピーコーディング!


    1. PostgreSQLテーブル名を単純に使用することはできません(関係は存在しません)

    2. SQLServerをSugarCRMに接続します

    3. T-SQL:文字列の連結の反対-文字列を複数のレコードに分割する方法

    4. pgBadgerを使用したPostgreSQLログ分析