2011-08-03 133 views
4

我有兩個MySQL表格說A和B.一個包含只有一個varchar列(讓我們打電話給一個A1)與約23000記錄。表B(70000條記錄)有更多的列,其中一個與表A中的A1相對應(讓我們稱之爲B1)。我想知道A的值不會在B中的相應列,所以我用:爲什麼這個查詢運行得這麼慢?

SELECT A1 
FROM A 
LEFT JOIN B 
    ON A1 = B1 
WHERE B1 IS NULL 

這兩列A1和B1都對他們的定義的索引。仍然這個查詢運行速度非常慢。我已經運行解釋,這是輸出:

id select_type table type possible_keys key  key_len ref rows Extra 
1 SIMPLE  A  index \N    PRIMARY 767  \N 23269 Using index 
1 SIMPLE  B  ALL  \N    \N  \N  \N 70041 Using where; Not exists 

更新:SHOW CREATE TABLE兩個表(改變了原來的名稱);

CREATE TABLE `A` (
    `A1` varchar(255) NOT NULL, 
    PRIMARY KEY (`A1`) 
) ENGINE=MyISAM DEFAULT CHARSET=utf8 


CREATE TABLE `B` (
    `col1` int(10) unsigned NOT NULL auto_increment, 
    `col2` datetime NOT NULL, 
    `col3` datetime default NULL, 
    `col4` datetime NOT NULL, 
    `col5` varchar(30) NOT NULL, 
    `col6` int(10) default NULL, 
    `col7` int(11) default NULL, 
    `col8` varchar(20) NOT NULL, 
    `B1` varchar(255) default NULL, 
    `col10` tinyint(1) NOT NULL, 
    `col11` varchar(255) default NULL, 
    PRIMARY KEY (`col1`), 
    KEY `NewIndex1` (`B1`) 
) ENGINE=MyISAM AUTO_INCREMENT=70764 DEFAULT CHARSET=latin1 

「諾特爾編輯:data_lengthindex_lengthSHOW TABLE STATUS

table data_length index_length 
A  465380  435200 
B  5177996  1344512 
+0

你在做表上的索引嗎? – ThoKra

+0

他在A1和B1上有索引 –

+0

有趣的是,如果我'取消'這個,那麼做一個右連接,只有在A1是NULL的情況下它會更快地完成 –

回答

2

的字符集,你是在外部比較兩列的JOIN不同。我不知道這是否是原因,所以我測試了這些結果:

SELECT A1 
FROM A 
LEFT JOIN B ON A1 = B1 
WHERE B1 IS NULL 

-- Table A..: 23258 rows, collation = utf8_general_ci 
-- Table B..: 70041 rows, collation = latin1_swedish_ci 
-- Time ....: I CANCELLED THE QUERY AFTER 20 MINUTES 

-- Table A..: 23258 rows, collation = latin1_swedish_ci 
-- Table B..: 70041 rows, collation = latin1_swedish_ci 
-- Time ....: 0.187 sec 

-- Table A..: 23258 rows, collation = utf8_general_ci 
-- Table B..: 70041 rows, collation = utf8_general_ci 
-- Time ....: 0.344 sec 

解決方法:使字符集的兩個表(或兩列ATLEAST)相同的。

+0

是的,這是一個很好的觀點。查詢中每一行的字符集轉換可能需要很長時間。 – Karolis

+0

你先生,真棒。謝謝,這工作。 –

0

看來A1B1較大精密組件。

你創造指數A1和B1都

確保它們被索引!

SELECT A1 
FROM A 
WHERE A1 NOT IN (
    SELECT B1 AS A1 From B; 
) 
+0

humm ...它不打破原始查詢的邏輯嗎? – heximal

+0

?它不會產生相同的結果嗎? –

+0

這不會產生相同的結果,並且運行速度很慢(5分鐘後還沒有完成) –

0

嘗試此查詢:

SELECT B1 
FROM B 
WHERE not B1 in (
    select A1 
    from a 
) 
+0

在我進行LEFT JOIN之前我已經嘗試過了,讓它運行幾個小時並且它沒有完成... –

+0

這肯定比較慢。發佈此答案之前,您是否運行過一個EXPLAIN? –

1

這個查詢將掃描表A的所有行,但如果你有B1索引那麼最有可能它不會掃描表B:

select A1 
from A 
where not exists (
    select * 
    from B 
    where B.B1 = A.A1 
) 

在運行此或您的原始查詢之前,您可能會嘗試運行ANALYZE TABLE以更新這些表的密鑰分發信息:

ANALYZE TABLE A, B 

如果沒有再幫你可以嘗試使用索引玩,比如:

select A1 
from A ignore index (PRIMARY) 
where not exists (
    select * 
    from B force index (NewIndex1) 
    where B.B1 = A.A1 
) 
+0

事實上,對這個查詢的EXPLAIN確實對兩個表都顯示type = index,但仍然「行」只顯示了總行數 –

+0

@Lex你可以給這些表的完整的'SHOW CREATE TABLE'輸出嗎? – Karolis

+0

我已經用'SHOW CREATE TABLE'的輸出更新了原始問題 –

0

如果我用你創建表的語句,並運行你的SELECT語句的解釋,我得到這樣的結果:

id select_type table type possible_keys key  key_len ref rows Extra 
1 SIMPLE  A  index NULL   PRIMARY 767  NULL 2  Using index 
1 SIMPLE  B  index NULL   NewIndex1 258  NULL 4  Using where; Using index 

在我的MySQL版本(5.1.41)使用索引不如預期,所以我認爲這可能是MySQL中已經修復的一個錯誤,假設你的索引是在創建的表格聲明中設置的。你使用什麼MySQL版本?