InnoDB 主键效率

Ben*_*rel 5 mysql innodb

我已经阅读了许多关于取决于存储引擎的主键效率的文章,但我很困惑。

给定一个简单的多对多表,其中包含两个字段storeIdzoneId以下哪种设计对 InnoDB 最有效,为什么?

  • 使用两个字段作为复合主键:
CREATE TABLE store_zone(
    storeId INT(10) UNSIGNED NOT NULL,
    zoneId  INT(10) UNSIGNED NOT NULL,
    PRIMARY KEY(storeId, zoneId)
);
Run Code Online (Sandbox Code Playgroud)
  • 使用特定的自增主键:
CREATE TABLE store_zone(
    id      INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
    storeId INT(10) UNSIGNED NOT NULL,
    zoneId  INT(10) UNSIGNED NOT NULL,
    PRIMARY KEY(id),
    UNIQUE KEY(storeId, zoneId)
);
Run Code Online (Sandbox Code Playgroud)

笔记:

  • 无论如何storeId,我需要 ( , zoneId) 对上的唯一键
  • 我有外键的storezone桌子,在这里没有显示可读性,所以在这两种情况下有上一个额外的要求指标zoneId,以及

Rol*_*DBA 5

分析

既然我们在谈论 InnoDB,那么让我们将gen_clust_index. 它是一个特殊的索引,它使 PRIMARY KEY 和关联的行数据可以从相同的 InnoDB 页面访问。

根据gen_clust_index 上的 MySQL 文档

  • 如果在表上定义 PRIMARY KEY,InnoDB 将使用它作为聚集索引。

  • 如果你没有为你的表定义 PRIMARY KEY,MySQL 会选择第一个只有 NOT NULL 列的 UNIQUE 索引作为主键,InnoDB 使用它作为聚集索引。

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

在这种情况下,您会真正感受到以下方面的效率或不足:

磁盘空间

将单个 auto_increment 列作为PRIMARY KEY使 PRIMARY KEY 的整体大小小于具有两列的大小。为什么?如果PRIMARY KEY是两个 INT 而不是一个,那么 BTREE 页面将是两倍大。如果您使用外键约束和二级索引,这会变得更加痛苦,因为它们随后也必须在大小上爆炸。

在这种情况下,您将选择第二个架构以更好地使用索引。

插入性能

将行数据插入具有两个 UNIQUE 索引的 InnoDB 表需要两倍的 BTREE 管理和唯一检查。

  • 一个用于 gen_clust_index(由 auto_increment 决定)
  • 一个用于另一个 UNIQUE 索引(由 决定(storeId, zoneId)

插入数百万行时,每个额外的 UNIQUE 索引的额外微秒会增加 CPU 时间。

在这种情况下,您将为更快的 INSERT 选择第一个模式。

结论

磁盘空间和插入性能问题几乎迫使您做出选择。显然,您选择与哪一个一起生活。如果使用表示 的外键约束(storeId, zoneId),则需要使用 auto_increment 作为外部表中的引用的第二个模式。