MySQL不使用复合主键的第一列

时间:2015-03-05 10:03:06

标签: mysql join primary-key composite-primary-key

我有一个带有以下键的大数据表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无法使用复合主键的第一列进行连接。 有没有人帮我?

1 个答案:

答案 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