[MySQL] ルールベースの最適化 (サブクエリの最適化、派生テーブル、マテリアライズド テーブル、半結合、スカラー サブクエリ、行サブクエリを含む)

コンセプト

  • 定数テーブル: 次の 2 つのクエリ メソッドによってクエリされるテーブル:

    • タイプ 1: クエリ テーブル一条记录都没有、または只有一条记录

    • タイプ 2:主键等值匹配または唯一二级索引列等值匹配as を使用して搜索条件テーブルをクエリする

  • 派生テーブル:FROM子句后面的子查询派生テーブルと呼ばれるテーブルに配置されます。

  • マテリアライゼーション: サブクエリの結果セット内のレコードを一時テーブルに保存するプロセス。

  • マテリアライズドテーブル:サブクエリの結果セットを格納する一時テーブル

    • メモリベースの実体化テーブルにはハッシュ インデックスがあります

    • ディスクベースの実体化テーブルにはB+ ツリー インデックスがあります

    • マテリアライズドテーブル内のレコードはすべてインデックス付けされているため、サブクエリ結果セットにオペランドが存在するかどうかをインデックスを使用して判断する場合、速度が非常に速くなり、サブクエリ文のパフォーマンスが向上します。

第14章 ルールベースの最適化(サブクエリ最適化を含む)

14.1 条件付き単純化

  1. 不要な括弧を削除する

  2. 絶えず通過する

  3. 無駄な条件を削除する

  4. 式の計算

  5. HAVING 句と WHERE 句の組み合わせ

    • 集計関数と GROUP BY 句がクエリ ステートメントに現れない場合は、それらをマージできます。
  6. 定数テーブルの検出

    • クエリ オプティマイザーがクエリ ステートメントを分析するときは、最初に定数テーブル クエリを実行し、次にクエリ内のテーブルに関係するすべての条件を定数に置き換え、最後に他のテーブルのクエリ コストを分析します。

14.2 外部結合の削除

  1. 外部結合と内部結合の本質的な違いは次のとおりです。

    • 外部接続の駆動テーブルのレコードについては、ON 句のフィルター条件に一致するレコードが駆動テーブルに見つからない場合でも、駆動テーブルのレコードが結果セットに追加され、各レコードは結果セットに追加されます。対応する駆動テーブル フィールドには NULL 値が入力されます。

    • ただし、インナーコネクションの駆動テーブルのレコードに駆動テーブルのON句のフィルタ条件に一致するレコードが見つからなかった場合、駆動テーブルのレコードは破棄されます。

  2. Null 拒否 (reject-NULL) : では外连接查询、指定されたWHERE子句包含はnull 拒否と呼ばれます被驱动表中的列不为NULL值条件

    • つまり、被驱动表的某个列適合性を明示的に指定するIS NOT NULLか、暗黙的に被驱动表的某个列適合性を直接指定する指定的值と、外部接続を内部接続に変換できます。

      select * from t1 left join t2 on t1.m1=t2.m2 where t2.n2 is not NULL;
      # 等价于
      select * from t1 inner join t2 on t1.m1 = t2.m2;
      
      select * from t1 left join t2 on t1.m1=t2.m2 where t2.n2 = 2;
      # 直接指定'被驱动表的某个列'符合指定的值,此时就能将 外连接 转为 内连接。
      
  3. 駆動テーブルの WHERE 句が NULL 値拒否の条件を満たした後、外部結合と内部結合を相互に変換できます。

  4. 利点: オプティマイザは、テーブルのさまざまな結合順序のコストを評価することにより、クエリを実行するための最もコストの低い結合順序を選択します。

14.3 サブクエリの最適化

14.3.1 サブクエリ構文

  1. サブクエリは、外部クエリのさまざまな場所に出現できます。

    • SELECT句内

    • FROM句内

    • WHERE 句または ON 句内

    • ORDER BY 句と GROUP BY 句では、構文ではサポートされていますが、意味がありません。

  2. 結果セットを返すことでサブクエリを区別します。

    • スカラー サブクエリ: 単一の値のみを返すサブクエリ。

    • 行サブクエリ: 1 つのレコードを返すサブクエリ (レコードには複数の列が含まれる場合があります)。

    • 列サブクエリ: 列のデータを検索します (この列には複数のレコードが含まれる場合があります)。

    • テーブル サブクエリ: サブクエリの結果には、多数のレコードと多数の列が含まれます。

  3. サブクエリは、外部クエリとの関係によって区別されます。

    • 相関のないサブクエリ: サブクエリは、外部クエリの値に依存せずに、構造を独立して実行できます。

    • 相関サブクエリ: サブクエリの実行は、外部クエリの値に依存します。

  4. ブール式でのサブクエリの使用

    1. ブール式の演算子として =、>、<、>=、<=、<>、!=、<=> を使用します。

      • 注: ここでのサブクエリは または のみです标量子查询行子查询つまり、サブクエリの結果は単一の値のみを返すか、レコードのみを返すことができます。
       # 标量子查询
       select * from t1 where m1 < (select MIN(m2 from t2); 
       
       # 行子查询
       select * from t1 where (m1,n1)=(select m2,n2 from t2 limit 1);
      
    2. [NOT] IN / ANY / SOME / ALL サブクエリは
      省略されます

    3. サブクエリが
      わずかに存在します

  5. サブクエリ構文の考慮事項

    • サブクエリは括弧で囲む必要があります。

    • SELECT 句のサブクエリはスカラー サブクエリである必要があります(from/where 句ではないことに注意してください)。

        # slect 子句中的子查询  是 标量子查询
        select (select m1, n1 from t1); 
        
        # where/from子句中的子查询 也可以是 行子查询
        ```
      
      
    • スカラー サブクエリまたは行サブクエリを取得したいが、サブクエリの結果セットにレコードが 1 つしか含まれていないことが保証できない場合は、LIMIT 1 ステートメントを使用してレコード数を制限する必要があります。

    • [NOT] IN / ANY / SOME / ALL サブクエリの場合、サブクエリ内で LIMIT ステートメントは許可されません。

      • 注: [NOT] IN / ANY / SOME / ALL サブクエリの場合、サブクエリ内で集計関数と HAVING 句を使用せずに ORDER BY 句、DISTINCT 句、および GROUP BY 句を使用しても意味がありません。サブクエリの結果は実際にはコレクションであるため、コレクション内の値が並べ替えられているかどうかは関係ありません。例えば:

        select * from t1 where m1 in (selct m2 from t2 order by m2);
        
      • 集計関数や HAVING 句がない場合、GROUP BY 句は単なる飾りです。例えば:

        select * from t1 where m1 in (selct m2 from t2 group by m2);
        
    • テーブルに対してサブクエリを実行しながら、1 つのステートメントで特定のテーブルのレコードを追加、削除、または変更することはできません。

14.3.2 MySQL でのサブクエリの実行方法

1. スカラー副問合せとロウ副問合せの実行方法

  1. 相関のないスカラー/行サブクエリ ステートメント: 外部クエリとサブクエリを独立して (2 つの単一テーブル クエリとして) 実行します。

  2. 相関スカラー/行サブクエリ ステートメント: 例 1、

    # 例1
    select * from s1 where 
        key = (select common_field from s2 where s1.key3 = s2.key3 limit 1);
    

    実装方法:

    • ステップ 1: 最初に外部クエリからレコードを取得します。例 1 では、まず s1 テーブルからレコードを取得します。

    • ステップ 2: 次に、このレコードからサブクエリに含まれる値を見つけます。例1では、テーブルs1で取得したレコードから列s1.key3の値を求め、サブクエリを実行します。

    • ステップ 3: 最後に、サブクエリのクエリ結果に従って、外側のクエリの WHERE 句の条件が true であるかどうかを確認します。確立されている場合は、外部クエリのレコードを結果セットに追加し、確立されていない場合は破棄します。

    • ステップ 4: 外側のクエリでレコードが取得できなくなるまでステップ 1 に進みます。

2. INサブクエリの最適化

  1. 提案された具体化されたテーブル。

    • マテリアライゼーション: サブクエリの結果セット内のレコードを一時テーブルに保存するプロセス。

    • マテリアライズドテーブル:サブクエリの結果セットを格納する一時テーブル

      • メモリベースの実体化テーブルにはハッシュ インデックスがあります

      • ディスクベースの実体化テーブルにはB+ ツリー インデックスがあります

      • マテリアライズドテーブル内のレコードはすべてインデックス付けされているため、サブクエリ結果セットにオペランドが存在するかどうかをインデックスを使用して判断する場合、速度が非常に速くなり、サブクエリ文のパフォーマンスが向上します。

  2. 結合する実体化されたテーブル

    # 查询1
    select * from s1
    where key1 in (slecet common_field from s2 where key3 = 'a);
    
    # 当把子查询物化之后,假设子查询物化表的名称为 materialized_table, 
    # 该物化表存储的子查询结果集的列为 m_val。
      
    # 则相当于表s1与子查询物化表 materialized_table进行内连接。
    # 即,查询1 等价于 查询2
    
    # 查询2
    select s1.* from s1 
    inner join materialized_table on key1 = m_val;
    
    • 内部結合に変換した後、クエリ オプティマイザーはさまざまな結合順序のコストを評価し、最もコストが低い方法を選択してクエリを実行できます。

    • 分析のコスト要素查询2(表s1和物化表materialized_table内连接):

      1. s1 テーブルが駆動テーブルとして使用される場合、クエリの総コストは次のようになります。
      • サブクエリの実現に必要なコスト。

      • s1 テーブルをスキャンするときのコスト。

      • s1 テーブル内のレコード数 x 条件 m_val=xxx を使用した、materialized_table テーブルへの単一テーブル アクセスのコスト (マテリアライズド テーブル内のレコードは繰り返されず、マテリアライズド テーブル内の列にはインデックスが付けられているため、この手順では実行されません)非常に速いです)。

      1. materialized_table テーブルが駆動テーブルとして使用される場合、クエリの合計コストは次のようになります。
      • サブクエリの実現に必要なコスト。

      • マテリアライズされたテーブルをスキャンするときのコスト。

      • マテリアライズされたテーブルのレコード数 x 条件 key1=xxx での s1 テーブルへの単一テーブル アクセスのコスト (このステップは、key1 列にインデックスが構築されているため非常に高速です)。

  3. サブクエリをセミ結合に変換する

    サブクエリを実体化してクエリを実行すると、一時テーブルを作成するコストが発生しますが、実体化を行わずにサブクエリを直接接続に変換することはできるでしょうか。

    # 查询1
    select * from s1
    where key1 in (slecet common_field from s2 where key3 = 'a);
    
    • 新しい概念の提案-セミジョイン

    • 注: セミ結合はIN サブクエリ用に最適化されています。

    • s1 テーブルと s2 テーブルの半結合とは、次のことを意味します。

      • s1 テーブルのレコードの場合、s2 テーブルに一致するレコードがあるかどうかのみを考慮し、それに一致するレコードの数は考慮しません。最終的な結果セットには、s1 テーブルのレコードのみが保持されます。

      • # 半连接,只是在MySQL内部采用的一种执行子查询的方式,
        # MySQL没有提供面向用户的半连接语法。
        # 所以此语句不能放在黑框框中运行。
        select s1.* from s1 SEMI JOIN s2
            on s1.key1 = s2.common_field
            where key3 = 'a';
        
    • 半結合方法 (戦略) を実装します。

      • テーブルの引き出し(サブクエリでのテーブルの引き出し)

      • Duplicate Weedout (重複値の除去)

      • LooseScan (ルーズスキャン)

      • 半結合の実体化

      • FirstMatch (最初の一致)

    • セミジョインの適用条件(以下の条件を満たすサブクエリのみセミジョインに変換可能)

      • サブクエリは IN 演算子で構成されるブール式である必要があり、外国都市クエリの WHERE 句または ON 句に現れる必要があります。

      • 外側のクエリには他の検索条件も含めることができますが、IN サブクエリの検索条件と接続するには AND 演算子を使用する必要があります。

      • サブクエリは、UNION で接続された複数のクエリではなく、単一のクエリである必要があります。

      • サブクエリには、GROUP BY、HAVING ステートメント、または集計関数を含めることはできません。

    • セミ結合には適していません

      • 外側のクエリのWHERE句では、INサブクエリで構成されるブール式に他の検索条件をOR演算子で連結する場合があります。

      • IN の代わりに NOT IN を使用する場合。

      • SELECT 句内の IN サブクエリの場合。

      • サブクエリには、GROUP BY、HAVING、または集計関数が含まれています。

      • サブクエリにUNIONが含まれる場合。

      • 相関関係のないサブクエリの場合は、クエリに参加する前に実体化を試みることができます。

      • IN サブクエリの試行は、サブクエリが相関しているかどうかに関係なく、EXISTS サブクエリに変換できます。

    • まとめ

      • IN サブクエリがセミ結合に変換するための条件を満たしている場合、クエリ オプティマイザーはまずサブクエリをセミ結合に変換し、次に次の 5 つのセミ結合実行戦略のどれが最もコストが低いかを検討します。最後に、サブクエリを実行するためのコストが最も低い実行戦略を選択します。

        • テーブルの引き出し(サブクエリでのテーブルの引き出し)

        • Duplicate Weedout (重複値の除去)

        • LooseScan (ルーズスキャン)

        • 半結合の実体化

        • FirstMatch (最初の一致)

      • IN サブクエリが準結合への​​変換条件を満たさない場合、クエリ オプティマイザーは、次の 2 つの戦略からサブクエリを実行する低コストの方法を見つけます。

        • まずサブクエリを実体化し、次にクエリを実行します。

        • IN から EXISTS への変換を実行します。

3. ANY / ALL サブクエリの最適化

[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-qxlXmvU4-1683462178280) (C:\Users\YUE\AppData\Roaming\marktext\)画像\2023-05- 07-19-57-24-image.png)]

4. [NOT] EXISTS サブクエリの実行

少し

5. 派生テーブルの最適化

  1. 派生テーブル:FROM子句后面的子查询派生テーブルと呼ばれるテーブルに配置されます。

  2. 派生テーブルを含むクエリの場合、MySQL は 2 つの実行戦略を提供します。

  • 派生テーブルを実体化する

    • アイデア: 派生テーブルの結果セットを内部一時テーブル (マテリアライズド テーブル) に書き込み、このマテリアライズド テーブルをクエリに参加するための通常のテーブルとして使用します。

    • 遅延具体化戦略: 派生テーブルがクエリで実際に使用されるとき、クエリを実行する前に派生テーブルを具体化するのではなく、派生テーブルを具体化しようとします。

  • 派生テーブルと外部クエリを結合します (つまり、派生テーブルを使用せずにクエリを書き直します)。

——読書メモ、「How MySQL Works」より抜粋

おすすめ

転載: blog.csdn.net/xiaoyue_/article/details/130547362