2011-01-10 4 views
0

ありがとうございました。クエリでGROUP BYを使用すると、MySQLテーブルのインデックス作成に関するヘルプ

2つのInnoDBテーブルがあります。

著者

id  INT 
nickname VARCHAR(50) 
status ENUM('active', 'blocked') 
about  TEXT 

ブック

author_id INT 
title  VARCHAR(150) 

は、私は各作者を取得するには、これらのテーブルに対してクエリを実行していますよ彼が持っている本の数:

SELECT a. * , COUNT(b.id) AS book_count 
FROM authors AS a, books AS b 
WHERE a.status != 'blocked' 
AND b.author_id = a.id 
GROUP BY a.id 
ORDER BY a.nickname 

このクエリは非常に遅いです(実行に約6秒かかる)。私はbooks.author_idのインデックスを持っており、それは完全に動作しますが、authorsテーブルのインデックスを作成する方法を知らないので、このクエリで使用することができます。ここで

はルックスをEXPLAINどのように現在ある:

id select_type table type possible_keys    key   key_len ref  rows Extra 
1 SIMPLE  a  ALL  PRIMARY,id_status_nickname NULL   NULL  NULL 3305 Using where; Using temporary; Using filesort 
1 SIMPLE  b  ref  key_author_id    key_author_id 5   a.id 2  Using where; Using index 

私はMySQL manual on optimizing queries with group by見てきましたが、私は私のクエリにそれを適用することができます方法を見つけ出すことができませんでした。

これについてのヒントやヒントをお読みいただきたいと思います.MySQLが使用できるように、インデックス構造でなければならないものは何ですか?

編集

私が試してみました:

(id, status, nickname) 
(status, nickname) 

はどちらも同じような状況になりました。

+0

インデックスの基本的な経験則は、あなたが結合やwhere句で使用しているフィールドにはインデックスを付ける必要があるということです。あなたの質問のために、それはa.id、b.author_id、およびaを意味します。ステータスはすべてインデックスに登録する必要があります。 –

答えて

3

id_status_nicknameが複合インデックス(id、status、nickname)であると仮定します。あなたのクエリでは、a.status!= blockedと言って行をフィルタリングします。これには次の問題があります。

  1. これに使用できるインデックスはありません。ステータスがそのインデックスのプレフィックスではないため、(ID、ステータス、ニックネーム)は使用できません。
  2. ステータスのインデックスがあると仮定すると、!=を使用すると使用できません。それをstatus = 'active'に変更する必要があります。
  3. また、状態は、2つの値を持つ列挙型フィールドであり、基数は低くなります。したがって、mysqlはインデックスをまったく使用しないことがあります。

これを試すことができます:indexを(status、id、nickname)として作成し、status = 'active'を使用してください。私の推測では、あなたが '='を使用しているので、ステータスがインデックスのプレフィックスであるため、このインデックスを選択してから、グループごとに使用してからby.heopeを使用してください。

UPDATE: WHERE句にORDER BYで使用されているフィールドがない場合、filesortを避けることはできないようです。

0

(ステータス、ニックネーム)でインデックスを試してみます。それは "filesortの使用"の必要性を取り除くはずです。