为什么MySQL多列索引人满为患?

为什么MySQL多列索引人满为患?,mysql,indexing,multiple-columns,Mysql,Indexing,Multiple Columns,考虑下表: CREATE TABLE `log` ( `what` enum('add', 'edit', 'remove') CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `with` int(10) unsigned NOT NULL, KEY `with_what` (`with`,`what`) ) ENGINE=InnoDB; INSERT INTO `log` (`what`, `with`) VALUES

考虑下表:

CREATE TABLE `log`
(
    `what` enum('add', 'edit', 'remove') CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
    `with` int(10) unsigned NOT NULL,

    KEY `with_what` (`with`,`what`)
) ENGINE=InnoDB;

INSERT INTO `log` (`what`, `with`) VALUES
    ('add', 1),
    ('edit', 1),
    ('add', 2),
    ('remove', 2);
据我所知,
with_what
索引在其第一个
with
级别上必须有2个唯一条目,在
what
子索引中必须有3个(编辑:4)唯一条目。但是MySQL报告每个级别有4个唯一的条目。换句话说,每个级别的唯一元素数始终等于
log
表中的行数

编辑:“第二级”的唯一条目数等于记录总数是可以的,但顶层不可以

EDIT2:注意到如果
列所占用的位数发生了变化,例如变为int(11)和int(10),则基数开始按预期工作。即使是
解释从日志中选择的计数(与“with”不同)
也会为
行显示足够的值


这是错误、功能还是我的误解?

你的理解是错误的。多列键是从多个值创建的,而不是为多列创建的。MySQL报告4个唯一的条目,因为您输入了4对唯一的条目

您已经为这些列描述了单独的索引,因此

KEY `with_what` (`with`,`what`)
应该是

KEY `with` (`with`),
KEY `what` (`what`)

它应该按照您的要求工作。

显示索引
显示近似的统计信息

在执行对表的查询时,会自动收集这些统计信息,此外,您还可以通过发出
ANALYZE table log
来强制手动收集这些统计信息

基数列中的值不精确,在调用
ANALYZE
之间可能会发生变化,即使基础表没有变化。

您应该将“多列”索引视为“串联索引”,这意味着在索引中串联各个列。也就是说,每行有一个索引项,该项包含所有索引列


看看我的电子书,全面了解索引的工作原理:

如果添加另一个条目('edit',1),它将报告5个唯一条目。这里有点不对劲。顺便说一句,我不需要单列索引。我的项目中的其他多列索引以正常方式运行,并且不会过多。例如,我有另一个
who\u when
索引,它的第一级唯一条目数等于用户数(
who
),而不是
log
表中的总行数。您的其他表也在InnoDB中吗?他们有主键吗?如果我没记错的话,InnoDB将通过将主键附加到非唯一键来尝试使键唯一。@Danosure:是的,所有使用InnoDB存储的表<代码>日志
表没有主键,其他表有。奇怪的是,即使在
log
表上,其他多列索引也没有这样的问题。也许有什么虫子什么的。我非常担心这个问题,因为
log
table是项目中增长最快的表。建立这么大的低效索引可能不会花费太多的时间和空间。你所说的“MySQL为每个级别报告4个唯一的条目”是什么意思?您在哪里查找?@Quassnoi:
显示表名中的索引
或在phpMyAdmin中查看表的结构选项卡。是否有方法查看确切的基数?我只是想知道为什么这是唯一一个基数极不准确的索引,而其他索引则完全准确。@actual:
SELECT COUNT(DISTINCT column)FROM mytable