1

構築中の分析アプリのバックエンドとして機能するスター スキーマを構築しています。私のクエリ ジェネレーターは、通常のスター結合パターンを使用してクエリを作成しています。以下のサンプル クエリでは、ファクト テーブルが 2 つのディメンション テーブルに結合され、エンド ユーザーが選択した定数値によってディメンション テーブルがフィルター処理されます。

MySQL 5.5 を使用しており、すべてのテーブルは MyISAM です。

この問題では、単純に最初の N 行 (この場合は最初の 1 行) を取得しようとしています。

EXPLAIN
SELECT fact_table.*
FROM
    fact_table
INNER JOIN
    dim1 ON (fact_table.dim1_key = dim1.pkey)  
INNER JOIN
    dim2 ON (fact_table.dim2_key = dim2.pkey)           
WHERE
    dim1.constant_value = 123
    AND dim2.constant_value = 456
ORDER BY
    measure1 ASC LIMIT 1

Explain の出力は次のとおりです。値に適用される一意のキーがあるため、両方のディメンション キーが定数値に解決されます。

*************************** 1. row ***************************
       id: 1
select_type: SIMPLE
    table: dim1
     type: const
possible_keys: PRIMARY,dim1_uk
      key: dim1_uk
  key_len: 8
      ref: const
     rows: 1
    Extra: Using filesort
*************************** 2. row ***************************
       id: 1
select_type: SIMPLE
    table: dim2
     type: const
possible_keys: PRIMARY,dim2_uk
      key: dim2_uk
  key_len: 8
      ref: const
     rows: 1
    Extra: 
*************************** 3. row ***************************
       id: 1
select_type: SIMPLE
    table: fact_table
     type: ref
possible_keys: my_idx
      key: my_idx
  key_len: 16
      ref: const,const
     rows: 50010
    Extra: Using where

ファクト テーブルのインデックスは次のとおりです。

show indexes from fact_table

*************************** 10. row ***************************
    Table: fact_table
 Non_unique: 1
 Key_name: my_idx
 Seq_in_index: 1
 Column_name: dim1_key
Collation: A
 Cardinality: 24
 Sub_part: NULL
   Packed: NULL
     Null: 
 Index_type: BTREE
  Comment: 
Index_comment: 
*************************** 11. row ***************************
    Table: fact_table
Non_unique: 1
 Key_name: my_idx
Seq_in_index: 2
Column_name: dim2_key
Collation: A
Cardinality: 70
 Sub_part: NULL
   Packed: NULL
     Null: 
Index_type: BTREE
  Comment: 
Index_comment: 
*************************** 12. row ***************************
    Table: fact_table
Non_unique: 1
 Key_name: my_idx
Seq_in_index: 3
 Column_name: measure1
Collation: A
Cardinality: 5643
 Sub_part: NULL
   Packed: NULL
     Null: 
Index_type: BTREE
  Comment: 
Index_comment: 

このクエリをプロファイリングすると、クエリがファイルソート操作の「結果のソート」の実行にほとんどの時間を費やしていることがわかります。私の質問は、正しいインデックスを使用している場合でも、なぜこのクエリは並べ替えを行わずに最初の値を単純に取り出せないのでしょうか? my_idx は既に右側の列でソートされており、計画に示されているように、インデックスで最初に表示される 2 つの列は定数として解決されます。

クエリを次のように書き直すと、ファイルの並べ替えなしで、目的のプランを取得できます。

SELECT fact_table.*
FROM
    fact_table
WHERE
    dim1_key = (select pkey from dim1 where constant_value = 123)
    AND dim2_key = (select pkey from dim2 where constant_value = 456)
ORDER BY
    measure1 ASC LIMIT 1

これらの SQL コマンドを生成するツールを変更するとコストがかかるため、クエリが元の形式で記述されている場合でも、このファイルソートは避けたいと考えています。

私の質問は、インデックスの最初のキーが (INNER JOIN を介して) 定数であり、インデックスが正しい順序でソートされている場合でも、MySQL がファイルソートを選択するのはなぜですか? これを回避する方法はありますか?

4

1 に答える 1

0

私の質問は、インデックスの最初のキーが (INNER JOIN を介して) 定数であり、インデックスが正しい順序でソートされている場合でも、MySQL がファイルソートを選択するのはなぜですか? これを回避する方法はありますか?

結果セットの順序は、JOIN の最初のテーブルの読み取りに使用されるインデックスに依存するためですが、EXPLAIN でわかるように、JOIN は実際にはdim1テーブルから開始されます。

奇妙に思えるかもしれませんが、暗黙的に MySQL の開始を強制するfact_tableには、ディメンション テーブルのインデックスを (constantvalue) ではなく (pkey, constantvalue) に変更する必要があります。そうしないと、MySQL オプティマイザーは、条件constantvalue=some_valueが最小行を返すテーブルから開始します。 . 問題は、他のクエリでこれらのインデックスが必要になる可能性があることです。

代わりに、STRAIGHT_JOIN オプションを SELECT に追加して、明示的に順序を強制することを試みることができます。

于 2013-11-01T16:17:20.147 に答える