14

この SQL SELECT を使用してビューを作成する予定ですが、その説明では、一時的なファイルソートを使用していることがわかります。この問題を解決するために必要なインデックスがわかりません。ほとんどの場合、インデックスを使用してソートするのではなく、ファイルソートを使用する理由が不思議です。

ここに私のテーブルがあります:

CREATE TABLE `learning_signatures` (
  `signature_id` int(11) NOT NULL AUTO_INCREMENT,
  `signature_file` varchar(100) NOT NULL,
  `signature_md5` varchar(32) NOT NULL,
  `image_file` varchar(100) NOT NULL,
  PRIMARY KEY (`signature_id`),
  UNIQUE KEY `unique_signature_md5` (`signature_md5`)
) ENGINE=InnoDB AUTO_INCREMENT=640 DEFAULT CHARSET=latin1

CREATE TABLE `learning_user_suggestions` (
  `user_suggestion_id` int(11) NOT NULL AUTO_INCREMENT,
  `signature_id` int(11) NOT NULL,
  `ch` char(1) NOT NULL,
  `time_suggested` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `user_id` int(11) NOT NULL,
  PRIMARY KEY (`user_suggestion_id`),
  KEY `char_index` (`ch`),
  KEY `ls_sig_id_indx` (`signature_id`),
  KEY `user_id_indx` (`user_id`),
  KEY `sig_char_indx` (`signature_id`,`ch`)
) ENGINE=InnoDB AUTO_INCREMENT=1173 DEFAULT CHARSET=latin1

そして、これが私の見解で使用しようとしている問題のある SQL ステートメントです。

select ls.signature_id, ls.signature_file, ls.signature_md5, ls.image_file, sug.ch , count(sug.ch) AS suggestion_count
from (`learning_signatures` `ls` left join `learning_user_suggestions` `sug` on(ls.signature_id = sug.signature_id))
group by ls.signature_id, sug.ch;

説明からの出力:

id  select_type table   type    possible_keys                   key             key_len ref                 rows    Extra
1   SIMPLE      ls      ALL     NULL                            NULL            NULL    NULL                514     "Using temporary; Using filesort"
1   SIMPLE      sug     ref     ls_sig_id_indx,sig_char_indx    ls_sig_id_indx  4       wwf.ls.signature_id 1

別の例として、今回は where 句を使用します。

explain select ls.signature_id, ls.signature_file, ls.signature_md5, ls.image_file, sug.ch , count(sug.ch) AS suggestion_count
from (`learning_signatures` `ls` left join `learning_user_suggestions` `sug` on(ls.signature_id = sug.signature_id))
WHERE signature_md5 = '75f8a5b1176ecc2487b90bacad9bc4c'
group by ls.signature_id, sug.ch;

出力の説明:

id  select_type table   type    possible_keys                key                    key_len ref     rows    Extra
1   SIMPLE      ls      const   unique_signature_md5         unique_signature_md5   34      const   1       "Using temporary; Using filesort"
1   SIMPLE      sug     ref     ls_sig_id_indx,sig_char_indx ls_sig_id_indx         4       const   1   
4

3 に答える 3

18

最初のクエリでは、署名テーブルをユーザーの提案と結合し、多数の行を取得してから、ユーザーの提案からいくつかの列を使用して結果をグループ化します。ただし、以前に結合されたテーブルで定義する必要があるため、グループ化に役立つ結合されたテーブルのインデックスはありません。代わりにすべきことは、すでに ch と signature_id でグループ化されているユーザーの提案から派生テーブルを作成してから結合することです。

SELECT ls.signature_id, ls.signature_file, ls.signature_md5, ls.image_file, 
       sug.ch, sug.suggestion_count
FROM learning_signatures ls
LEFT JOIN 
  (SELECT s.signature_id, s.ch, count(s.ch) as suggestion_count
    FROM learning_user_suggestions s 
    GROUP BY s.signature_id, s.ch ) as sug
ON ls.signature_id = sug.signature_id

オプティマイザーは、グループ化に sig_char_indx インデックスを使用できるようになりました。派生テーブルは署名テーブルよりも大きくなく、一意の列を使用して両方を結合します。シグニチャ テーブルをフル スキャンする必要がありますが、いずれにせよすべてを選択しているため、これを避けることはできません。

2 番目のクエリについては、署名を 1 つに制限したい場合は、追加するだけです

WHERE ls.signature_md5='75f8a5b1176ecc2487b90bacad9bc4c'

とにかく、1 つの signature_id だけが md5 と一致するため、前のクエリの最後に s.ch だけでグループ化します。オプティマイザーは、現在、where には md5 インデックスを使用し、グループ化には char_index を使用する必要があります。

于 2011-05-02T17:49:44.040 に答える
0

signature_md5 と signature_id の両方を (この順序で) 含む learning_signatures のインデックスを作成すると役立つかもしれません。

`KEY `md5_id` (`signature_md5`,`signature_id`)?

私は MySQL の専門家ではありませんが、where 句と join 句の両方をカプセル化するキーを作成すると、通常は一時的なファイルソートを取り除くのに役立つことがわかりました

于 2011-05-02T16:13:16.927 に答える