2011-10-27 55 views
2

我有這個查詢(如下所示),其中當前使用臨時文件和文件夾爲了生成一組按順序結果分組。如果可能,我想擺脫他們的使用。我查看了這個查詢中使用的底層索引,我只是看不到缺少的內容。使用臨時文件優化MySql查詢

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輸出:

+----+-------------+-------+--------+--------------------------------+----------------+---------+----------------------------------+------+----------+----------------------------------------------+ 
| 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語句爲每個表如下圖所示,讓你知道的模式。

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; 

任何指導將不勝感激。

回答

3

的文件排序很可能是因爲您對ORDER BY

它在MySQL "ORDER BY Optimization"文檔提到沒有合適的索引。

你可以做的是加載臨時表,然後從中選擇。加載臨時表時,請使用ORDER BY NULL。當您從臨時表中選擇時,請使用ORDER BY .. LIMIT

問題是該組添加隱含的order by <group by clause> ASC,除非通過添加order by null來禁用該行爲。
這是那些MySQL特定問題之一。

+0

這是當我刪除GROUP BY子句,雖然'使用filesort'消失! – GordyD

+0

@GordyD:這就是爲什麼我給出了這個答案:-) – gbn

+0

更改ORDER BY子句的東西與索引使用filesort沒有什麼區別,但它。只有當我完全刪除GROUP BY時,纔會使用任何文件夾。爲什麼你的回答與此有關呢? – GordyD

0

我可以看到兩個可能的優化,

  1. b.approved =「1」 - 你絕對需要快速過濾覈准列的索引。

  2. f2.facebook_id IN([這裏有很多facebook的ids]) - 將facebook的id存儲在臨時表中。然後在臨時表上創建一個索引,然後與臨時表連接,而不是使用IN子句。

+0

'1.b.approved ='1' - 您肯定需要在批准列上進行快速篩選的索引.'因爲批准是布爾字段且基數較低,MySQL將拒絕使用索引。 – Johan