2

mysql結合に関する知識が行き詰まり、実行しようとしているクエリに時間がかかりすぎています...自分でmysqlを学習するのはほんの少しですが、読むことに時間を費やしました。インデックスと結合の仕組みについて、多くのgoogle検索を実行し、いくつかの異なるクエリ形式を試しました。無駄に、助けが必要です。

まず、私のデータベースは、現時点では、selectクエリの速度に合わせて最適化されていると言えます。インデックスが多すぎることはわかっています...mysqlを学習する私の理論は、インデックスを多すぎて、mysqlオプティマイザーが私の目的のために何を選択するかを調べ(explainを使用して決定)、なぜそのインデックスを選択したのかを判断することです。

とにかく、私は4つのテーブルを持っています:table1、table2、table3、table4 ...

table1.ID1は主キーであり、table1の他のデータはtable2の複数のコンテンツに分割される場合があります。table2.ID1は、コンテンツフォームtable1に基づいて作成されたtable1のすべてのエントリを識別します。table2.ID2は、テーブル2のプライマリキーです。table3.ID2は、コンテンツフォームtable2に基づいて作成されたtable3のすべてのエントリを識別します。 ID3は、コンテンツフォームtable3に基づいて構築されたtable4のすべてのエントリを識別します

table1のすべてのエントリがtable2に対応するデータを持っているわけではなく、同様にtable2はtable3に、table3はtable4にあります。

私がする必要があるのは、日付範囲内に表示されるID2の個別の値を取得することです。また、table2のコンテンツが最終的にtable4に表示される場合に限ります。私が直面している課題は、table1だけに日付列があり、table4にも表示されるエントリのみが必要なことです。

次のクエリには約2分かかります。

select table2.ID2 from table1 
left join table2 on
table1.ID1 = table2.ID1
left join table3 on
table3.ID2 = table2.ID2 
left join table4 on
table4.ID3 = table3.ID3
where table1.Date between "2012-03-11" and "2012-03-18

上記のクエリでexplainを使用することで、これほど時間がかかる理由がわかりません。

+----+-------------+--------------+-------+----------------------+----------+---------+------------------------------+-------+--------------------------+
| id | select_type | table        | type  | possible_keys        | key      | key_len | ref                          | rows  | Extra                    |
+----+-------------+--------------+-------+----------------------+----------+---------+------------------------------+-------+--------------------------+
|  1 | SIMPLE      | table1       | range | ...                  | Datekey  | 9       | NULL                         | 17528 | Using where; Using index |
|  1 | SIMPLE      | table2       | ref   | ...                  | ID1key   | 8       | mydata.table1.POSTID         |     1 |                          |
|  1 | SIMPLE      | table3       | ref   | ...                  | ID2key   | 8       | mydata.table2.SrcID          |    20 |                          |
|  1 | SIMPLE      | table4       | ref   | ...                  | ID3key   | 8       | mydata.table3.ParsedID       |    10 | Using index              |
+----+-------------+--------------+-------+----------------------+----------+---------+------------------------------+-------+--------------------------+

可能なキーの名前を「...」に置き換えました。それほど重要ではないためです。いずれの場合も、キーが選択されます。

さらに、クエリの結果セットの行数は、Explain結果セットの一致するとされる17528行よりもはるかに多くなります。どうしてもっと多いの?

私は何が間違っているのですか?運が悪かったので、インナージョインも試しました。クエリを解釈する方法は、4方向のベン図であり、基準が重複する行の数が非常に少なく、日付範囲のインデックスによってさらに最適化されています。

'distinct(table2.ID2)'を追加すると、少なくとも必要な結果セットが得られますが、それ以外の場合は、予想よりもはるかに長い結果セットが得られるのはなぜですか。また、なぜこれほど時間がかかるのでしょうか。

質問の一部があいまいな場合は申し訳ありませんが、必要に応じて明確にさせていただきます。

ありがとう、ブライアン

編集:

データベースがかなり大きくなり、かなりの数の一意の行識別子が必要になると予想されるため、すべてのインデックスはBIGINT列を参照します...おそらくbigintはやり過ぎであり、その列のサイズを小さくするか、インデックスによって処理がさらに高速化されます。

以下の受け入れられた答えに基づいた私の最終的な解決策は次のとおりです。

select ID2 from table2
where exists
    (select 1 from table1 r
    where table1.Date between "2012-03-11" and "2012-03-18" and table2.ID1 = table1.ID1
    )
and exists
    (select 1 from table3
    where exists 
        (select 1 from table4 where table4.ID3 = table3.ID3) 
    )

さらに、table2.ID1とtable2.ID2を関連付けるマルチフィールドインデックスが欠落していることに気付きました...このインデックスを追加した後、このステートメントは約11秒で返され、約20,000行を返します。

各テーブルの行数を考慮すると、これは妥当だと思います。table1:〜480,000 table2:〜480,000 table3:〜6,000,000 table4:〜60,000,000

これは効率的に聞こえますか?これが私が期待する最高のパフォーマンスであることを確認した後、私は答えを受け入れます。私は3GBのメモリ、ubuntu 12.04、mysql5.5.24を備えたXeon3GHzシステムで実行しています

4

1 に答える 1

2

おそらく、テーブル間に複数の一致があります。table1 が table2 の 5 行と table3 の 10 行に一致するとします。その後、出力に 50 行が表示されます。

これを解決するには、結合をテーブルごとに 1 行に制限する必要があります。

1 つの方法は、in 句を使用することです。フィルタリングに結合を使用している場合は、代わりに where 句を使用できます。

where table2.id1 in (select table1.id1 from table1)

「in」は重複を防ぎます。

もう 1 つの方法は、結合を実行して結合内のクエリを事前に集約することです。

Mysql は、最適化の観点から、where 句に対してわずかに異なる構造を好むようです。

where exists (select 1 from table1 where table1.id = table2.id)
于 2012-07-29T02:36:33.243 に答える