Mysql 复合索引基数在所有字段上并不相同

标签 mysql indexing cardinality compound-index

我已经在 mysql 上创建了一个复合索引,这是我使用的命令: 使用 BTREE 在 DELIVER_SM(AID,STATUSID,RETRY_CNT) 上创建索引 Deliver_aid_sid_rcnt_idx; 奇怪的是我对每个字段都有不同的基数值。这正常吗?我还创建了其他复合索引,每个字段的基数值是相同的。

+--------------+-----------------+-------------+--------------------------+-------------+
| TABLE_SCHEMA | TABLE_NAME      | COLUMN_NAME | INDEX_NAME               | CARDINALITY |
+--------------+-----------------+-------------+--------------------------+-------------+
| prddb        | DELIVER_SM      | AID         | deliver_aid_sid_rcnt_idx |          28 |
| prddb        | DELIVER_SM      | STATUSID    | deliver_aid_sid_rcnt_idx |         286 |
| prddb        | DELIVER_SM      | RETRY_CNT   | deliver_aid_sid_rcnt_idx |         286 |
+--------------+-----------------+-------------+--------------------------+-------------+
 

最佳答案

索引基数不是列的不同值的数量,而是 B 树索引中的节点的数量。

考虑下面的例子:

CREATE TABLE abc(   a int, b int, c int );

set @x = 0;
INSERT INTO abc( a, b, c ) 
SELECT (@x:=@x+1),
       round( @x / 10 ),
       round( @x / 100 )
FROM information_schema.columns
LIMIT 421;

CREATE INDEX ix1 ON abc( a, b, c );
CREATE INDEX ix2 ON abc( c, b, a );

ANALYZE TABLE abc;

以及显示索引基数的查询:

SELECT COUNT( distinct a) a,
       COUNT( distinct b) b,
       COUNT( distinct c) c,
       COUNT( * )
FROM abc;

SELECT table_name, index_name, column_name, cardinality
FROM INFORMATION_SCHEMA.STATISTICS
WHERE table_name = 'abc' AND index_name = 'ix1';

SELECT table_name, index_name, column_name, cardinality
FROM INFORMATION_SCHEMA.STATISTICS
WHERE table_name = 'abc' AND index_name = 'ix2';


查看此演示以查看结果:http://www.sqlfiddle.com/#!2/b5987/1

该表有 421 行。
a 列有 421 个不同的值。
b 列有 43 个不同的值。
c 列有 5 个不同的值。

我的抽屉很差,所以我不在这里附上这些 b 树索引的图:)
但我希望你能在脑海中想象出一张 B 树索引的图片,就像这个链接一样:http://docs.oracle.com/cd/E11882_01/server.112/e25789/indexiot.htm
(顺便说一句,我建议您学习这份 Material ,它与 Oracle 相关,而不是 MySql,但它很好地解释了索引如何工作以及它们如何组织)。 enter image description here

对于 ix1 ON abc( a, b, c ) 索引 MySql 显示以下基数:
一个 --> 407
b --> 407
c --> 407

请记住,基数不是精确值,而是估计值。

这里 a 是索引中的前导列(这是具有最多不同值的列),因此它在索引中创建了大量顶级节点。其余列(它们的值)也存储在这些顶级 inode 中(或者可能“之下”)。

将鼠标悬停在 ix2 ON abc( c, b, a ) 上,基数估计值不同:
c --> 9
b --> 101
--> 407

在这种情况下,其中c是索引的前导列,MySql“认为”(估计)索引有9个“顶级”节点,b的值取“c 下面”有 101 个节点,a 在索引中占用 407 个节点。

关于Mysql 复合索引基数在所有字段上并不相同,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18976804/

相关文章:

mysql - Rails根据需求查询条件

php - 如何根据 php 条件显示隐藏 html 表格行

mysql - 了解 MySQL 中的索引

mysql - 在 ubuntu 上使用 apache 和 passenger 运行 rails 应用程序

php - Laravel 4 的 whereIn() 在找到第一个值后是否停止获取行?

SQL Server 聚集索引 - 索引问题的顺序

hadoop - 如何使用外部表和 serde 优化 Hive queires

Redis Hyperloglog 限制

sql - 具有复合主键的表的基数不好