2016-07-20 26 views
-1

我正在爲某些數據構建扁平化查詢,並且我得到了導致查詢突然從0.031s運行到2.460中運行的這個外鍵秒。我分析了查詢,並且正在完成連接,因爲ALL加入了額外的Using where; Using join buffer (Block Nested Loop)而不是eq_ref連接。MySql加入類型古怪(使用「ALL」而不是「eq_ref」)

爲了弄清楚發生了什麼,我製作了兩張表的副本,並將它們剝離到最低限度。表定義如下:

CREATE TABLE `zz_submission` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `rcId` int(11) DEFAULT NULL, 
    PRIMARY KEY (`id`), 
    KEY `idx_rcId` (`rcId`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8; 

CREATE TABLE `zz_rc` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `name` varchar(255) NOT NULL, 
    PRIMARY KEY (`id`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8; 

zz_rc有5行的名稱。 zz_submission有5行,來自RC的有效ID。

當我運行此查詢 「類型」 爲表rall

explain SELECT 
    s.ID, 
    r.name 
FROM zz_submission s 
    LEFT JOIN zz_rc r ON s.rcId = r.id 
; 

Image 1

當我運行此查詢 「類型」 爲表req_ref

explain SELECT 
    s.ID, 
    r.id 
FROM zz_submission s 
    LEFT JOIN zz_rc r ON s.rcId = r.id 
; 

Image 2

爲什麼選擇連接表中的ID vs Name列會影響連接類型?我在原始查詢中測試了它,並再次切換回0.031s。

我能做些什麼來使查詢在這裏使用eq_ref join?

+0

您沒有顯示解釋輸出總計行數。你的問題缺乏細節 – Drew

+0

你剝奪了他們太多。對於** 5 **行,掃描表比使用任何索引要快。 –

+0

對不起,我添加了解釋輸出。 – William

回答

0

您的查詢似乎已經閱讀了整個s表,然後讀取了很多或全部的r表,對嗎?

Using join buffer表示它將所需的數據從r加載到緩衝區中。這可以通過指數快速掃描(PK,在你的情況下)。然後,查找可以在RAM中完成,而不會進一步觸擊r

第一個SELECT需要idname;第二隻需要id。基於數據類型(並且我沒有知識,或者優化器沒有那個VARCHAR龐大的知識),人們會猜測[id,name]比[id]要大得多。

「加入緩衝區」的大小有限制 - SHOW VARIABLES LIKE 'join_buffer_size';。所以它可能包含[id]的所有內容,但對[id,name]不夠大。

你真的有names任何地方接近255個字符?你的例子可能是一個很好的例子,爲什麼255不應該是每個人的默認值。

eq_ref意味着它將在r中進行合理有效的查找。但這可能會比Using join buffer慢。

Block Nested Loop大致意思是:循環遍歷s,達到每行的r

每個連接都可能分配一個「連接緩衝區」,所以不要使其大於RAM的1%。

+0

正確。 S是我的主表,我從中得到了所有的行。我正在從R加入FK以獲取狀態名稱。我不明白爲什麼連接類型和執行時間會根據我從連接表中選擇哪一列而發生如此劇烈的變化。 – William