2014-11-13 17 views
0

請注意,我問這個問題上dba.stackexchange.com,但我想我會後在這裏太:子查詢的執行慢時沒有匹配

在MySQL中,我有兩個基本的表格 - 帖子和關注:

CREATE TABLE Posts (
    id int(11) NOT NULL AUTO_INCREMENT, 
    posted int(11) NOT NULL, 
    body varchar(512) NOT NULL, 
    authorId int(11) NOT NULL, 
    PRIMARY KEY (id), 
    KEY posted (posted), 
    KEY authorId (authorId,posted) 
) ENGINE=InnoDB; 

CREATE TABLE Followers (
    userId int(11) NOT NULL, 
    followerId int(11) NOT NULL, 
    PRIMARY KEY (userId,followerId), 
    KEY followerId (followerId) 
) ENGINE=InnoDB; 

我有以下查詢,這似乎是優化不夠:

SELECT p.* 
    FROM Posts p 
    WHERE p.authorId IN (SELECT f.userId 
          FROM Followers f 
         WHERE f.followerId = 9 
         ORDER BY authorId) 
ORDER BY posted 
    LIMIT 0, 20 

EXPLAIN輸出:

+------+--------------------+-------+-----------------+--------------------+---------+---------+------------+------+--------------------------+ 
| id | select_type  | table | type   | possible_keys  | key  | key_len | ref  | rows | Extra     | 
+------+--------------------+-------+-----------------+--------------------+---------+---------+------------+------+--------------------------+ 
| 1 | PRIMARY   | p  | index   | NULL    | posted | 4  | NULL  | 20 | Using where    | 
| 2 | DEPENDENT SUBQUERY | f  | unique_subquery | PRIMARY,followerId | PRIMARY | 8  | func,const | 1 | Using index; Using where | 
+------+--------------------+-------+-----------------+--------------------+---------+---------+------------+------+--------------------------+ 

followerId是一個有效的id(意思是說,它實際上存在於兩個表中)時,查詢執行幾乎是立即的。但是,當表中沒有id時,查詢僅在7秒延遲後返回結果(空集)。

這是怎麼發生的?有沒有辦法在沒有匹配的情況下加快查詢速度(而不必提前檢查)?

回答

0

有沒有辦法加快這個查詢...... ???

是的。你應該做兩件事。

首先,您應該使用EXISTS而不是IN(交叉引用SQL Server IN vs. EXISTS Performance)。它會加速有匹配的情況,隨着數據集的增長,它會派上用場(現在速度可能會很快,但這並不意味着您不應該遵循最佳做法,在這種情況下,EXISTS是比IN更好的做法)

其次,你應該修改你的第二個表上的鍵只是一點點。你是一個良好的開始使用的(用戶ID,followerId)的複合鍵,但在優化這個特定的查詢方面,你需要牢記的MySQL索引的「最左前綴」的規則,如

如果表具有多列索引,則優化器可以使用該索引的任何最左邊的前綴來查找行。 http://dev.mysql.com/doc/refman/5.6/en/multiple-column-indexes.html

什麼從說明的是告訴你的是,SQL認爲它更有意義的加盟追隨者帖子(使用帖子的主鍵)和過濾對於給定followerId結果關閉該指數的查詢執行計劃。想象一下,「向我展示所有可能的匹配,然後將其縮減爲僅匹配followerId = {}的那些」

如果用複合鍵(followerId,userId)替換followerId鍵,則應該能夠快速放大到與給定followerID關聯的用戶標識符,並針對這些標識符進行存在檢查。

我希望我知道如何更好地解釋這個......這是一種強硬的概念,直到你有一個「啊哈」!時刻,它點擊。但是,如果您查看索引中最左邊的前綴規則,並將followerId上的鍵更改爲(followerId,userId)上的鍵,我認爲它會加快它的速度。如果您使用EXISTS而不是IN,即使您的數據集增長,也可以幫助您保持這一速度。

+0

能否請您提供一個具體的例子澄清? 「EXISTS」查詢不能用作「IN」的直接替換;此外,雖然我明白你在說什麼,但如果你能提供實際的查詢(以及對錶格所做的任何更改),這將會有所幫助。 – Melllvar

+0

'選擇頁。* FROM 帖子p WHERE EXISTS(SELECT * FROM關注WHERE p.authorid = Followers.userId AND followers.followerId = 9) ORDER BY張貼 LIMIT 0,20' – evanv

+0

在實際的變化方面到表格: 'ALTER TABLE跟隨者DROP KEY followerId;' 'ALTER TABLE關注者ADD KEY follower_user(followerId,userId);' – evanv

0

試試這個:

SELECT p.* 
FROM Posts p 
inner join Followers f On f.userId = p.authorId 
WHERE f.followerId = 9 
ORDER BY posted 
    LIMIT 0, 20 
+0

請添加一些解釋以使其對於其他讀者也有價值(例如指出您的解決方案與OP的解決方案相比有所不同)。 –

+0

我認爲, 執行查詢的性能取決於某種原因。 表中的數據量,db連接是否有效,查詢是否有效等。 在這種情況下我們正在討論的是查詢效率。 查詢優化效率因SQL Server,Oracle或MySQL等不同而有所不同。 我喜歡'evanv'查詢,它在Oracle中運行良好,但在mySQL中我從不嘗試。 我只是舉例查詢,我通常使用。 通常我的查詢將在SQL Server和MySQL中運行良好。 只需嘗試。 –