2011-10-27 16 views
2

私はこのクエリ(下に示す)を使用しています。は現在、テンポラリファイルとファイル番号を使用しています。可能であれば、その使用法を取り除きたいと思います。私はこのクエリで使用される基礎となるインデックスを調べましたが、何も見当たりません。スキーマを知っているので、各テーブルのテンポラリファイルセットとファイルセットを使用してMySqlクエリを最適化する

+----+-------------+-------+--------+--------------------------------+----------------+---------+----------------------------------+------+----------+----------------------------------------------+ 
| id | select_type | table | type | possible_keys     | key   | key_len | ref        | rows | filtered | Extra          | 
+----+-------------+-------+--------+--------------------------------+----------------+---------+----------------------------------+------+----------+----------------------------------------------+ 
| 1 | SIMPLE  | f  | index | PRIMARY,institutionId   | institutionId | 4  | NULL        | 308 | 100.00 | Using index; Using temporary; Using filesort | 
| 1 | SIMPLE  | f2 | ref | facebook_id_idx,school_uid_idx | school_uid_idx | 9  | f.school_uid      | 1 | 100.00 | Using where         | 
| 1 | SIMPLE  | b  | eq_ref | PRIMARY      | PRIMARY  | 4  | f.institutionId     | 1 | 100.00 | Using where         | 
+----+-------------+-------+--------+--------------------------------+----------------+---------+----------------------------------+------+----------+----------------------------------------------+ 

CREATE TABLE文は以下の通りである:ここでは

SELECT 
    b.institutionid AS b__institutionid, 
    b.name AS b__name, 
    COUNT(DISTINCT f2.facebook_id) AS f2__0 
FROM education_institutions b 
LEFT JOIN facebook_education_matches f ON b.institutionid = f.institutionid 
LEFT JOIN facebook_education f2 ON f.school_uid = f2.school_uid 
WHERE 
    (
    b.approved = '1' 
    AND f2.facebook_id IN ([lots of facebook ids here ]) 
) 
GROUP BY b__institutionid 
ORDER BY f2__0 DESC 
LIMIT 10 

EXPLAIN EXTENDED出力されます。

CREATE TABLE facebook_education (
    education_id int(11) NOT NULL AUTO_INCREMENT, 
    name varchar(255) DEFAULT NULL, 
    school_uid bigint(20) DEFAULT NULL, 
    school_type varchar(255) DEFAULT NULL, 
    year smallint(6) DEFAULT NULL, 
    facebook_id bigint(20) DEFAULT NULL, 
    degree varchar(255) DEFAULT NULL, 
    PRIMARY KEY (education_id), 
    KEY facebook_id_idx (facebook_id), 
    KEY school_uid_idx (school_uid), 
    CONSTRAINT facebook_education_facebook_id_facebook_user_facebook_id FOREIGN KEY (facebook_id) REFERENCES facebook_user (facebook_id) 
) ENGINE=InnoDB AUTO_INCREMENT=484 DEFAULT CHARSET=utf8; 

CREATE TABLE facebook_education_matches (
    school_uid bigint(20) NOT NULL, 
    institutionId int(11) NOT NULL, 
    created_at timestamp NULL DEFAULT NULL, 
    updated_at timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP, 
    PRIMARY KEY (school_uid), 
    KEY institutionId (institutionId), 
    CONSTRAINT fk_facebook_education FOREIGN KEY (school_uid) REFERENCES facebook_education (school_uid) ON DELETE CASCADE ON UPDATE CASCADE, 
    CONSTRAINT fk_education_institutions FOREIGN KEY (institutionId) REFERENCES education_institutions (institutionId) ON DELETE CASCADE ON UPDATE CASCADE 
) ENGINE=InnoDB DEFAULT; 

CREATE TABLE education_institutions (
    institutionId int(11) NOT NULL AUTO_INCREMENT, 
    name varchar(100) NOT NULL, 
    type enum('School','Degree') DEFAULT NULL, 
    approved tinyint(1) NOT NULL DEFAULT '0', 
    deleted tinyint(1) NOT NULL DEFAULT '0', 
    normalisedName varchar(100) NOT NULL, 
    created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, 
    PRIMARY KEY (institutionId) 
) ENGINE=InnoDB AUTO_INCREMENT=101327 DEFAULT CHARSET=utf8; 

ご指導いただければ幸いです。私は2つの可能な最適化を見ることができます

答えて

3

filesortレコードはおそらく起こります。

あなたができることは、テンポラリテーブルをロードすることです。それ以降はテンポラリテーブルを選択します。一時テーブルを読み込むときは、ORDER BY NULLを使用します。テンポラリテーブルから選択するとORDER BY .. LIMIT

order by nullを追加してその動作を無効にしない限り、そのグループは暗黙のorder by <group by clause> ASCを追加するという問題があります。
これはMySQL固有の問題点の1つです。

+0

GROUP BY句を削除すると、 'using filesort'が表示されなくなります。 – GordyD

+0

@GordyD:だからこそ私はこの答えを与えました:-) – gbn

+0

ORDER BY句をインデックス付きのものに変更すると、filesortを使っても違いはありません。 GROUP BYを完全に削除しただけで、filesortが使用されていません。私はあなたの答えがなぜこれに関連するのか、まったくわからない。 – GordyD

0

  1. b.approved =「1」を - あなたは間違いなく迅速なフィルタリングのために承認された列に索引を必要とします。

  2. f2.facebook_id IN([たくさんのfacebook ids]) - FacebookのIDを一時表に保存します。次に、tempテーブルにインデックスを作成し、IN句を使用する代わりにtempテーブルと結合します。あなたはそれがMySQLの"ORDER BY Optimization"ドキュメントに記載されます

    BY ORDERための適切なインデックスを持っていないので

+0

'1.b.approved = '1' - 承認されたフィールドがあり、カーディナリティが低いため、クイックフィルタリングのために承認されたカラムにインデックスが必要です。インデックス。 – Johan