主键的大小对表大小有影响吗?

agi*_*DBA 4 mysql innodb index primary-key

我有一个表(InnoDB),数据长度约为 36G,索引长度为 23G。

它有一个跨三列的复合主键。

作为减小此表大小的初步尝试,我删除了主键(实际上并不需要)。然而,数据长度和索引长度是相同的。

这是意料之中的吗?

在此数据库上启用UPDATE innodb_file_per_table

更新

mysql> show create table event;

CREATE TABLE `event` (
`owner_id` varchar(36) NOT NULL,
`key_id` varchar(255) NOT NULL,
`value` varchar(255) NOT NULL,
KEY `owner_id_idx` (`owner_id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 
Run Code Online (Sandbox Code Playgroud)

Rol*_*DBA 5

简答

恰恰相反:表的大小会影响主键的大小。因此,是的,这是意料之中的

长答案

主键位于gen_clust_index 中,也就是聚集索引。

根据聚集索引上的 MySQL 文档

聚集索引如何加快查询速度

通过聚集索引访问一行很快,因为行数据位于索引搜索引导的同一页上。如果表很大,与使用与索引记录不同的页面存储行数据的存储组织相比,聚簇索引体系结构通常可以节省磁盘 I/O 操作。(例如,MyISAM 将一个文件用于数据行,另一个用于索引记录。)

根据这个描述,InnoDB 存储引擎的每一行都位于聚集索引内。

有鉴于此,有两个问题需要回答:

  1. 为什么删除 PRIMARY KEY 不会缩小聚集索引?
  2. 为什么 OPTIMIZE TABLE 不收缩聚集索引?

这两个问题的答案只有一个。聚集索引上的 MySQL 文档说:

如果 table 没有 PRIMARY KEY 或合适的 UNIQUE 索引,则 InnoDB 在包含行 ID 值的合成列上内部生成隐藏的聚集索引。行按 InnoDB 分配给此类表中行的 ID 排序。行 ID 是一个 6 字节的字段,随着插入新行而单调增加。因此,按行 ID 排序的行在物理上是按插入顺序排列的。

想一想:OPTIMIZE TABLE由于您没有尝试删除任何行,因此变得无效。由于您没有删除任何行,因此行占用的所有空间仍将位于聚集索引内。您只是将一个键(您的主键)换成了另一个(6 字节的行 ID)。

缩小聚集索引的方法有哪些?

我有您可能需要执行的三 (3) 项技术之一

技巧#1:减少列的长度

  • 缩小INTs到 SMALLINT 或 TINYINT
  • 缩小VARCHAR(255)VARCHAR(128)

技术#2:删除旧行

  • 寻找具有真正旧时间戳的行,然后
    • 删除旧行
    • 将旧行存档在另一个表中

技巧#3:从表中删除列

  • 这在理论上是正确的
  • 没有人想在过程中丢失数据
  • 在删除列之前归档表

警告

在应用这三 (3) 种技术之一之前,请备份您的表

结语

一旦您应用了这三 (3) 项技术之一,您就可以执行以下操作之一来缩小聚集索引(例如,mydb.mytable):

  • OPTIMIZE TABLE mydb.mytable;
  • ALTER TABLE mydb.mytable ENGINE=InnoDB;

试一试 !!!

更新 2013-06-17 07:34 EDT

这是你的最后一条评论

因此,如果原始主键大于 6 字节,我是否不希望看到聚集索引大小减少?

即使PRIMARY KEY是 now CHAR(255),每一行都位于聚集索引内。InnoDB 中的每个页面都是 16K。6 字节的行 ID(InnoDB 仍然在内部使用)仍然嵌入在相同的页面中。丢弃PRIMARY KEY比物理丢弃更像是一种逻辑丢弃。这就是为什么我之前说

您只是将一个键(您的主键)换成了另一个(6 字节的行 ID)

删除 的物理行为PRIMARY KEY可能需要在逻辑删除(标记)每一行中跑到每一行,而不是使用某些内部列组合,PRIMARY KEY而是恢复到行 ID。这几乎不会改变 16K InnoDB 页面的使用,无论行长度是长(可能允许页面内有几行)还是短(可能允许页面内有更多行)。

运行OPTIMIZE TABLE缩小它仍然不会产生任何明显的变化,因为聚集索引的标记机制仍然存在。给定表中行的平均长度,完全相同的行数使聚集索引保持相同的大小。

查看我之前提到的三种技术和集群索引上的 MySQL 文档。给定表中的行数和您当前的表定义,如果您无法减小列大小、删除列、删除行并将它们归档到其他地方,那么您将无法缩小表。