代理项 (INT) 键是否几乎总是比唯一自然 (VARCHAR) 键(在 MySQL 中)产生更好的性能?
Does a surrogate (INT) key almost always yield better performance than an unique natural (VARCHAR) key (in MySQL)?
我很难理解 MySQL 数据库 table.
使用什么数据类型
假设我们是一家图书出版公司,我们需要在 MySQL 数据库中创建一个包含所有图书和作者的数据库。我们有大约 500000 本书。一本书有唯一的 ISBN(例如 978-3-16-148410-0
)。
所以我们有两种选择来存储我们的书:
- 创建一个
id VARCHAR(24) NOT NULL
自然主键列并将我们的 ISBN 存储在那里,或者
- 创建一个代理
id INT NOT NULL AUTO_INCREMENT
然后还有一个 isbn UNIQUE VARCHAR(24)
列
据我了解,普遍的共识是不要使用 VARCHAR(n)
作为主键,因为它需要更多的存储和性能来进行查找和连接,通常这对我来说很有意义。
但是,如果我们所有的操作都针对 ISBN(SELECT * FROM books WHERE isbn = ?
、UPDATE
、DELETE
等)- 为什么不使用 VARCHAR(24)
作为主键?
我很难理解,如果你有一个 immutable 自然键(比如一本书的 ISBN),并且 95% 的数据库操作无论如何都需要使用该字段,那么不应该使用 VARCHAR(24)
总是优于代理键设计?
我觉得这里有一个代理 AUTO_INCREMENT INT
键,完全没有意义。它没有任何好处。
或者在确定主键时我是否遗漏了一些基本知识。
我会使用 ISBN 作为主键。
MySQL 的默认存储引擎 InnoDB 中的主键查找比通过二级索引查找更有效。
的确,整数比 24 字符的 varchar 占用更少的存储空间 space,但在您的情况下,我假设您无论如何都必须存储 ISBN。如果您可以使用整数 而不是 ISBN,那将节省存储空间。
上面关于自然键往往会违反唯一性的评论通常是一个很好的警告。违规行为通常来自市场部。 ;-)
但是对于给定的数据集,您可以确定自然键没有重复项。如果您确实在阅读图书馆馆藏中的 ISBN 时遇到错误,图书馆员将不得不手动解决该问题。但我不希望这种情况经常发生在 500,000 本书中。
提示:使用二进制排序规则定义varchar,进行字符串比较会更快一些。例如:
CREATE TABLE Books (
isbn varchar(24) COLLATE utf8mb4_bin,
-- ...other columns...
PRIMARY KEY (isbn)
) DEFAULT CHARSET=utf8mb4;
代理性能(一般性讨论)
“几乎总是”?号
AUTO_INCREMENT 甚至不用于加入 - 如果您有“自然 PK”,为什么还要麻烦它;它需要 space 而没有提供任何好处。
UUID/GUID -- 通常更糟。这是由于缺少“参考地点”。
Many-to-many 映射 table -- 总是更糟。 Best:自然PK就是ids对。辅助密钥是一对,但顺序相反。
Space:由于PK被默默地包含在每个二级索引中,PK越大,二级索引就越庞大。如果您只有一个二级索引,那么大小就是一个折腾。副手多了两个,space就被啃光了
PK上的范围扫描。如果您需要使用 BETWEEN(等),那么将该范围键作为 PK 通常是有益的。相反,如果范围扫描正在通过二级索引(非常有效),但随后必须进入数据的 BTree,这将是很多额外的工作。
“索引合并”。一些 DB 供应商通过收集“行标识符”执行 AND 或 OR,然后对列表进行 and'ing 或 or'ing。然后查找实际行。 InnoDB 的结构方式,这几乎不值得做。
参考地点。 auto-inc 值按大致时间顺序排列数据。这可能是一个好处。或者它可能不会。获取传感器数据或股票报价。主要查询根据 sensor_id 或股票代码或作者或用户查找多行,而不是日期时间,但数据到达 time-order。实际上(总体)PRIMARY KEY(ticker, datetime)
更好。 (或者,如果可能存在重复,则 PRIMARY KEY(sensor_id, datetime, id), INDEX(id)
。)我看到一个 系统 以这种方式重新安排最大 table 的 PK 时,吞吐量翻了一番。
我已经创建了数百(数千?)个 table。浏览他们的 PK,我发现只有 1/3 使用 AUTO_INCREMENT
代理 PK。
底线:由于我每次键入时都会思考您的问题 CREATE TABLE
,我会说“自然”键在 2/3 的情况下更好。
查看ISBN
关闭您的特定 ISBN。看看你的 tables。您有一个 'wants' 以 ISBN 作为其 PK,对吗?您多久加入一次table? table 上有多少二级索引?你可能从来没有做过像 WHERE ISBN > "..."
这样的范围查询,对吗?
如果您有 id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY
,您可能还会有 UNIQUE(isbn)
。但反之则不然。
ISBN
应该是 VARCHAR(24) CHARACTER SET ascii COLLATE ascii_bin
。这对速度和 space.
都有帮助(一点点)
我很难理解 MySQL 数据库 table.
使用什么数据类型假设我们是一家图书出版公司,我们需要在 MySQL 数据库中创建一个包含所有图书和作者的数据库。我们有大约 500000 本书。一本书有唯一的 ISBN(例如 978-3-16-148410-0
)。
所以我们有两种选择来存储我们的书:
- 创建一个
id VARCHAR(24) NOT NULL
自然主键列并将我们的 ISBN 存储在那里,或者 - 创建一个代理
id INT NOT NULL AUTO_INCREMENT
然后还有一个isbn UNIQUE VARCHAR(24)
列
据我了解,普遍的共识是不要使用 VARCHAR(n)
作为主键,因为它需要更多的存储和性能来进行查找和连接,通常这对我来说很有意义。
但是,如果我们所有的操作都针对 ISBN(SELECT * FROM books WHERE isbn = ?
、UPDATE
、DELETE
等)- 为什么不使用 VARCHAR(24)
作为主键?
我很难理解,如果你有一个 immutable 自然键(比如一本书的 ISBN),并且 95% 的数据库操作无论如何都需要使用该字段,那么不应该使用 VARCHAR(24)
总是优于代理键设计?
我觉得这里有一个代理 AUTO_INCREMENT INT
键,完全没有意义。它没有任何好处。
或者在确定主键时我是否遗漏了一些基本知识。
我会使用 ISBN 作为主键。
MySQL 的默认存储引擎 InnoDB 中的主键查找比通过二级索引查找更有效。
的确,整数比 24 字符的 varchar 占用更少的存储空间 space,但在您的情况下,我假设您无论如何都必须存储 ISBN。如果您可以使用整数 而不是 ISBN,那将节省存储空间。
上面关于自然键往往会违反唯一性的评论通常是一个很好的警告。违规行为通常来自市场部。 ;-)
但是对于给定的数据集,您可以确定自然键没有重复项。如果您确实在阅读图书馆馆藏中的 ISBN 时遇到错误,图书馆员将不得不手动解决该问题。但我不希望这种情况经常发生在 500,000 本书中。
提示:使用二进制排序规则定义varchar,进行字符串比较会更快一些。例如:
CREATE TABLE Books (
isbn varchar(24) COLLATE utf8mb4_bin,
-- ...other columns...
PRIMARY KEY (isbn)
) DEFAULT CHARSET=utf8mb4;
代理性能(一般性讨论)
“几乎总是”?号
AUTO_INCREMENT 甚至不用于加入 - 如果您有“自然 PK”,为什么还要麻烦它;它需要 space 而没有提供任何好处。
UUID/GUID -- 通常更糟。这是由于缺少“参考地点”。
Many-to-many 映射 table -- 总是更糟。 Best:自然PK就是ids对。辅助密钥是一对,但顺序相反。
Space:由于PK被默默地包含在每个二级索引中,PK越大,二级索引就越庞大。如果您只有一个二级索引,那么大小就是一个折腾。副手多了两个,space就被啃光了
PK上的范围扫描。如果您需要使用 BETWEEN(等),那么将该范围键作为 PK 通常是有益的。相反,如果范围扫描正在通过二级索引(非常有效),但随后必须进入数据的 BTree,这将是很多额外的工作。
“索引合并”。一些 DB 供应商通过收集“行标识符”执行 AND 或 OR,然后对列表进行 and'ing 或 or'ing。然后查找实际行。 InnoDB 的结构方式,这几乎不值得做。
参考地点。 auto-inc 值按大致时间顺序排列数据。这可能是一个好处。或者它可能不会。获取传感器数据或股票报价。主要查询根据 sensor_id 或股票代码或作者或用户查找多行,而不是日期时间,但数据到达 time-order。实际上(总体)
PRIMARY KEY(ticker, datetime)
更好。 (或者,如果可能存在重复,则PRIMARY KEY(sensor_id, datetime, id), INDEX(id)
。)我看到一个 系统 以这种方式重新安排最大 table 的 PK 时,吞吐量翻了一番。我已经创建了数百(数千?)个 table。浏览他们的 PK,我发现只有 1/3 使用
AUTO_INCREMENT
代理 PK。
底线:由于我每次键入时都会思考您的问题 CREATE TABLE
,我会说“自然”键在 2/3 的情况下更好。
查看ISBN
关闭您的特定 ISBN。看看你的 tables。您有一个 'wants' 以 ISBN 作为其 PK,对吗?您多久加入一次table? table 上有多少二级索引?你可能从来没有做过像 WHERE ISBN > "..."
这样的范围查询,对吗?
如果您有 id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY
,您可能还会有 UNIQUE(isbn)
。但反之则不然。
ISBN
应该是 VARCHAR(24) CHARACTER SET ascii COLLATE ascii_bin
。这对速度和 space.