我有一个带有以下键的大数据表tbl1:
PRIMARY KEY (`log_id`,`entry_id`,`position`),
KEY `idx_log_id` (`log_id`)
列定义:
log_id bigint(20) unsigned NOT NULL,
entry_id mediumint(8) unsigned NOT NULL,
position tinyint(3) unsigned NOT NULL,
affiliate_id mediumint(8) unsigned NOT NULL,
和一个只有一个键的小表tbl2:
KEY `ix_log_id` (`log_id`,`affiliate_id`)
列定义:
log_id bigint(20) unsigned NOT NULL,
affiliate_id bigint(21) unsigned DEFAULT NULL,
两个表都具有相同的引擎(MyISAM)和字符集。
我打算加入他们。
explain
select *
from
tbl1,
tbl2
where
tbl1.log_id = tbl2.log_id
and tbl1.affiliate_id = tbl2.affiliate_id;
它看起来不错。扫描tbl2(2.5m行),并使用KEY idx_log_id
将每行与tbl1连接,基数为4.很好。
现在我认为:KEY idx_log_id
索引与我的主键的第一列相同的列。所以它没有必要。实际上,EXPLAIN显示PRIMARY,idx_log_id为可能的密钥。
现在我做
explain
select *
from
tbl1 ignore key (idx_log_id),
tbl2
where
tbl1.log_id = tbl2.log_id
and tbl1.affiliate_id = tbl2.affiliate_id;
并且忽略了idx_log_id,我希望mysql使用主键。
但不是。而不是使用来自tbl1的密钥,它对tbl1执行全表扫描,这超过40亿行,并且将它们与来自tbl2的ix_log_id连接,这远远低于。
我正在使用mySQL 5.1,但我无法解释为什么mySQL无法使用复合主键的第一列进行连接。 有没有人帮我?
答案 0 :(得分:1)
我在这里发现了可能的问题: mySQL没有为主键创建正确的统计信息。复合PK的第一列和第二列的基数为NULL,只有最后一列具有基数(等于表中的行数)。由于第一个键列没有基数,因此优化器无法使用此列进行连接。
这似乎是一个可重现的问题。当我在测试表上创建复合索引时,索引的所有列都具有基数。对于同一列上的主键,除最后一列外,所有列的基数均为NULL。
ANALYZE TABLE修复了这个问题,但对于生产中的大表或表来说是不可行的。
我不确定这是否是我们特定版本的错误,或者更常见的是mySQL。我们使用的版本: 73年5月1日 - rel14.11日志 (Percona Server(GPL),14.11,Revision 603)
分析后的关键统计数据:
Table Non_unique Key_name Seq_in_index Column_name Cardinality
tbl1 0 PRIMARY 1 log_id 840106431
tbl1 0 PRIMARY 2 entry_id 840106431
tbl1 0 PRIMARY 3 position 4200532155
tbl1 1 idx_log_id 1 log_id 840106431
之前,它看起来像这样:
分析前的关键统计数据:
Table Non_unique Key_name Seq_in_index Column_name Cardinality
tbl1 0 PRIMARY 1 log_id <null>
tbl1 0 PRIMARY 2 entry_id <null>
tbl1 0 PRIMARY 3 position 4200532155
tbl1 1 idx_log_id 1 log_id 840106431