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

MySQL does not use first column of a composite primary key

我有一个大数据 table 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,

和一个较小的 table tbl2,只有一个键:

KEY `ix_log_id` (`log_id`,`affiliate_id`)

列定义:

log_id bigint(20) unsigned NOT NULL,
affiliate_id bigint(21) unsigned DEFAULT NULL,

两个 table 具有相同的引擎 (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 与基数为 4 的 tbl1 连接。太棒了。

现在我想: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 的键,而是对超过 40 亿行的 tbl1 进行了完整的 table 扫描,并将它们与来自 tbl2 的 ix_log_id 相结合,后者远远逊色。

我正在使用 mySQL 5.1,我无法解释为什么 mySQL 无法使用复合主键的第一列进行连接。 有人帮我吗?

我在这里发现了可能的问题: mySQL 没有为主键创建正确的统计信息。复合 PK 的第一列和第二列的基数为 NULL,只有最后一列有基数(等于 table 中的行数)。由于第一个键列没有基数,优化器无法使用此列进行连接。

这似乎是一个可重现的问题。当我在测试 table 上创建复合索引时,索引的所有列都有一个基数。对于同一列上的主键,除最后一列外的所有列的基数都是 NULL。

ANALYZE TABLE 解决了这个问题,但对于生产中的大 tables 或 tables 是不可行的。

我不确定这是我们特定版本的错误,还是 mySQL 的一般错误。我们使用的版本: 5.1.73-rel14.11-日志 (Percona 服务器 (GPL),14.11,修订版 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