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

UNIONALLと組み合わせたテーブルのVIEWのMySQLパフォーマンス

    ビル・カーウィンの優れた回答のすべての点に同意します。

    Q: 議論されたユニオンクエリのビューを作成し、それを結合、副選択などで使用するのは通常の方法ですか?

    A: MySQLの場合、より一般的な方法は、「CREATEVIEW」ステートメントの使用を避けることです。

    Q: パフォーマンスの観点から、結合、副選択などに挿入するだけの場合と比較して、より悪い、同等、またはより良いでしょうか?

    A: ビューオブジェクトを参照すると、同等のインラインビューと同じパフォーマンスになります。

    (ビューオブジェクトを検索し、特権を確認してから、ビュー参照を保存されたSQLに置き換えるには、ほんの少し長いステートメントを送信するのではなく、少しだけ作業が必要になる場合があります。ただし、これらのいずれも違いは重要ではありません。)

    Q: この場合、ビューを持つことの欠点はありますか?

    A: 最大の欠点は、ビューが保存されているかインラインであるかにかかわらず、MySQLがビューを処理する方法にあります。 MySQLは常にビュークエリを実行し、そのクエリの結果を一時的なMyISAMテーブルとして具体化します。ただし、ビュー定義が保存されているか、インラインに含まれているかに違いはありません。 (他のRDBMSは、MySQLとはかなり異なる方法でビューを処理します。)

    ビューの大きな欠点の1つは、外部クエリの述語がビュークエリにプッシュダウンされないことです。そのビューを参照するたびに、単一のID値のクエリがある場合でも、MySQLはビュークエリを実行して一時的なMyISAMテーブル(インデックスなし)を作成し、MySQLはその一時的なものに対して外部クエリを実行しますMyISAMテーブル。

    したがって、パフォーマンスの観点から、「CREATE TEMPORARY TABLE t (cols) ENGINE=MyISAM」と同等のビューへの参照を考えてみてください。 "および"INSERT INTO t (cols) SELECT ... "。

    MySQLは実際にはインラインビューを「派生テーブル」と呼んでおり、MySQLがそれを使って何をしているのかを理解すると、その名前は非常に意味があります。

    私の個人的な好みは、「CREATEVIEW」ステートメントを使用しないことです。 (私が見ているように)最大の欠点は、実行中のSQLを「隠す」ことです。将来の読者にとって、ビューへの参照は表のように見えます。そして、SQLステートメントを作成するときに、テーブルのようにビューを参照するので、非常に便利です。次に、別の参照を使用して、そのテーブルをそれ自体に結合することを決定します。 (2番目の参照では、MySQLもそのクエリを再度実行し、さらに別の一時的な(インデックス付けされていない)MyISAMテーブルを作成します。これにJOIN操作があります。次に、述語 "WHERE view.column='foo'"が追加されます。外側のクエリで。

    最終的に、最も明白なパフォーマンスの向上を「非表示」にし、その述語をビュークエリにスライドさせます。

    次に、誰かがやって来て、古いビューを参照する新しいビューを作成することを決定します。彼は行のサブセットのみを必要とし、何かを壊す可能性があるため既存のビューを変更できないため、新しいビューを作成します... CREATE VIEW myview FROM publicview p WHERE p.col='foo'。

    そして、myviewへの参照は、最初にpublicviewクエリを実行し、一時的なMyISAMテーブルを作成します。次に、myviewクエリがそれに対して実行され、外部クエリが実行される別の一時的なMyISAMテーブルを作成します。

    基本的に、ビューの利便性には、意図しないパフォーマンスの問題が発生する可能性があります。データベース上で誰でも使用できるビュー定義を使用すると、最適なソリューションではない場合でも、誰かがそれを使用することになります。

    少なくともインラインビューでは、SQLステートメントを作成する人は、実行されている実際のSQLをよりよく認識しており、SQLをすべてレイアウトすることで、パフォーマンスを調整する機会が得られます。

    私の2セント。

    TAMING BEASTLY SQL

    通常のフォーマットルール(私のツールが自動的に行う)を適用すると、巨大なSQLを読み取って操作できるものに曲げることができることがわかりました。

    SELECT row.col1
         , row.col2
         , person.*
      FROM some_table row
      LEFT
      JOIN ( SELECT 'person'  AS `person_type`
                  , p.id      AS `id`
                  , CONCAT(p.first_name,' ',p.surname) AS `name`
               FROM person p
              UNION ALL
             SELECT 'company' AS `person_type`
                  , c.id      AS `id`
                  , c.name    AS `name`
               FROM company c
           ) person
        ON person.id = row.person_id
       AND person.person_type = row.person_type
    

    同様に、インラインビューをまったく避け、SELECTリストで条件式を使用する可能性がありますが、これにより、多くの列で扱いにくくなります。

    SELECT row.col1
         , row.col2
         , row.person_type AS ref_person_type
         , row.person_id   AS ref_person_id
         , CASE
           WHEN row.person_type = 'person'  THEN p.id 
           WHEN row.person_type = 'company' THEN c.id
           END AS `person_id`
         , CASE
           WHEN row.person_type = 'person'  THEN CONCAT(p.first_name,' ',p.surname)
           WHEN row.person_type = 'company' THEN c.name
           END AS `name`
      FROM some_table row
      LEFT
      JOIN person p
        ON row.person_type = 'person'
       AND p.id = row.person_id
      LEFT
      JOIN company c
        ON row.person_type = 'company'
       AND c.id = row.person_id
    


    1. MYSQL全文検索とLIKE

    2. すでに閉じられているオブジェクトsqlitedatabaseを再度開こうとします

    3. JpaSpecificationExecutor JOIN + ORDER BY in Specification

    4. 2つのデータベースの構造を比較しますか?