MySQL 中的复合主键性能缺陷
Posted
技术标签:
【中文标题】MySQL 中的复合主键性能缺陷【英文标题】:Composite Primary Key performance drawback in MySQL 【发布时间】:2010-11-30 10:26:19 【问题描述】:我们有一个包含三个字段的复合主键的表(它在 mysql 5.1 中)。该表每秒有近 200 次插入和 200 次选择,表的大小约为 100 万行,并且还在增加。
我的问题是:“复合主键”是否会降低该表上插入和选择的性能?
我应该使用简单的自动递增 INT ID 字段而不是复合主键吗? (我认为答案与 MySQL 处理多列索引的方式有很大关系)
【问题讨论】:
【参考方案1】:INSERT
和 UPDATE
性能差异不大:(INT)
和 (INT, INT)
键几乎相同。
SELECT
复合材料PRIMARY KEY
的性能取决于许多因素。
如果您的表是InnoDB
,则该表隐式聚集在PRIMARY KEY
值上。
这意味着如果两个值都包含键,则搜索这两个值会更快:不需要额外的键查找。
假设您的查询是这样的:
SELECT *
FROM mytable
WHERE col1 = @value1
AND col2 = @value2
表格布局是这样的:
CREATE TABLE mytable (
col1 INT NOT NULL,
col2 INT NOT NULL,
data VARCHAR(200) NOT NULL,
PRIMARY KEY pk_mytable (col1, col2)
) ENGINE=InnoDB
,引擎只需要在表本身中查找确切的键值。
如果您使用自动增量字段作为假 id:
CREATE TABLE mytable (
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
col1 INT NOT NULL,
col2 INT NOT NULL,
data VARCHAR(200) NOT NULL,
UNIQUE KEY ix_mytable_col1_col2 (col1, col2)
) ENGINE=InnoDB
,那么引擎首先需要在索引ix_mytable_col1_col2
中查找(col1, col2)
的值,从索引中检索行指针(id
的值)并通过id
再次查找在表格本身中。
但是,对于 MyISAM
表,这没有区别,因为 MyISAM
表是堆组织的,行指针只是文件偏移量。
在这两种情况下,都将创建相同的索引(用于PRIMARY KEY
或UNIQUE KEY
)并以相同的方式使用。
【讨论】:
【参考方案2】:如果是 InnoDB,复合主键将包含在每个二级索引的每个条目中。
这意味着
您的二级索引将占用与这些列 + 主键中的所有列一样多的空间 如果所需的所有列都包含在二级索引 + pk 中,则可以使用二级索引作为覆盖索引当然,这些分别是缺点和优点。
复合主键不一定是坏事,有时它们真的很有帮助,因为 InnoDB 将它们聚集在一起——这意味着使用比非- 聚集索引。
当然,如果您在其他表中有外键,它们会更宽,并且需要包含主表中的整个键。
但总的来说,我会说不。拥有复合主键本身不会导致问题。但是,如果有一个“大”主键(例如大 varchars)可能会超过集群和能够使用覆盖索引的优势。
【讨论】:
这是否意味着如果我在(reviewId,userId)
上有我的主键并且在(userId)
上有一个二级索引,那么这个索引将在内部包含(userId,reviewId,userId)
?
@Benjamin 是的,你是对的。此处dev.mysql.com/doc/refman/5.7/en/innodb-index-types.html 和本书shop.oreilly.com/product/0636920022343.do 中已明确说明【参考方案3】:
-
使用复合主键会稍微降低
SELECT
s 的速度,但效果几乎可以忽略不计,不值得担心。
将这些列编入索引完全会减慢您的INSERT
s,而且您肯定已经为INSERT
s 做了足够的担心。如果它是一个 MyISAM 表,其中INSERT
锁定了该表,这比它是一个 InnoDB 表更令人担忧。如果通过使用 auto_increment 主键,您可以使这些列不被索引,那么您将从更改中受益。但是,如果您仍需要为这三列保留索引(例如,如果您需要对它们的组合强制执行唯一性),那么在性能方面不会对您做任何事情。
【讨论】:
以上是关于MySQL 中的复合主键性能缺陷的主要内容,如果未能解决你的问题,请参考以下文章