2017-07-28 99 views
6

我有兩張桌子。 order_details是100,000行,而outbound是10,000行。爲什麼使用子查詢顯着加快此簡單聯接查詢?

我需要將它們加入名爲order_number的列,這兩列上都是VARCHAR(50)。 order_number在出站表中不唯一。

CREATE TABLE `outbound` (
    `outbound_id` int(12) NOT NULL, 
    `order_number` varchar(50) NOT NULL 
) ENGINE=InnoDB DEFAULT CHARSET=utf8; 

CREATE TABLE `order_details` (
    `order_details_id` int(12) NOT NULL, 
    `order_number` varchar(50) NOT NULL 
) ENGINE=InnoDB DEFAULT CHARSET=utf8; 

這是我的初步查詢,它需要超過60秒運行:

SELECT o.order_number 
FROM outbound o 
INNER JOIN order_details od 
    ON o.order_number = od.order_number 

該查詢得到同樣的結果和需要不到一秒鐘來運行:

SELECT o.order_number 
FROM outbound o 
INNER JOIN 
(
    SELECT order_number 
    FROM order_details 
) od 
ON (o.order_number = od.order_number) 

這對我來說令人感到意外,因爲通常子查詢顯着較慢。

正在運行EXPLAIN(我仍在學習如何理解)顯示子查詢版本使用derived2表,它使用的是索引,該索引是auto_key0。我不夠明白如何解釋這一點,以理解爲什麼這會產生重大影響。

我正在命令行上運行這些查詢。

我正在運行MySQL Ver 14.14 Distrib 5.6.35,用於Linux(x86_64)CentOS。

總結:

爲什麼這個簡單的用一個子查詢顯著更快的連接查詢?

+0

MySQL的糟糕的優化器?你是否與「EXISTS」或「IN」進行比較? 'SELECT o.order_number FROM出站ö WHERE EXISTS(SELECT ORDER_NUMBER FROM ORDER_DETAILS AS OD WHERE o.order_number = od.order_number)'或'SELECT o.order_number FROM出站ö WHERE ORDER_NUMBER IN ( SELECT order_number FROM order_details )' – dnoeth

+0

@dnoeth第一個查詢佔用了一分鐘,第二個查詢是即時的。 – Goose

+1

正如我所說的,一個體面的優化器應該對待所有四個類似的(實際上,當order_details.orde_number不唯一時,連接可能會得到不同的結果)。 – dnoeth

回答

5

我對MySQL的知識非常有限。但這些是我的想法:

您的表沒有索引。 然後,連接必須讀取整個第二個表,以便比較第一個表的每一行。

子查詢讀取第二個表並創建一個索引,然後它不需要爲第一個表的每一行讀取整個第二個表。它只需檢查索引,速度要快得多。

要驗證我是否正確,請嘗試爲兩個表(CREATE INDEX ...)中的列order_number創建索引,然後再次運行這兩個查詢。你的第一個查詢應該只用不到一秒而不是一分鐘。

+0

將數據下載到我的開發人員來測試這是一種痛苦,但是當我做到這些時,我發現您的答案是準確的。感謝你的回答,是有道理的。 – Goose