2011-08-03 119 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版本?