假设我有一个具有以下结构的表,出于示例目的过于简化:
表“人员”:
CREATE TABLE Persons (
id BIGINT(20) NOT NULL AUTO_INCREMENT,
name VARCHAR(255) NOT NULL,
address VARCHAR(255) NOT NULL,
telephone VARCHAR(255) NOT NULL,
biography LONGTEXT,
description LONGTEXT,
PRIMARY KEY (id)
)
假设“People”数据库中有 1000 个条目,而“传记”和“描述”的大小最多可达几 MB。
在下面的示例查询中,我选择所有 Person 并仅读取小数据,即使我不将它们包含在 SELECT 查询中,列biography
和列是否会影响我的查询性能?description
SELECT name, address, telephone FROM Persons;
是否最好移动biography
到description
专用表以避免性能损失(如果有)?
这取决于。
表的所有行都以称为数据页的组物理存储在磁盘上。默认情况下,MySQL 中的数据页大小为 16 KB。每当您查询表时,都需要找到包含您请求的数据的所有页面并将其从磁盘加载。您的查询不要求的列和行可能恰好与您的查询要求的列和行位于同一数据页中。显然,从磁盘加载更多数据(即更完整的数据页)将需要更长的时间。但它通常可以忽略不计,因为 16 KB 的数据页非常细粒度。开销相当小。
例外情况是对于较大的行和列的数据,它们通常存储在“行外”,这意味着该行的其余部分位于数据页之外。一般来说,页中存储了某种指针相反,这将两者重新联系在一起。因此,当您的查询请求这些数据页时,如果您的查询不要求这些数据,则不需要从磁盘加载这些非常大的行外数据。
当它们达到行外存储的阈值时则不需要。正如我在上一段中所讨论的,这就是数据库系统本质上在磁盘级别为您自动化的操作。
UPDATE
将这些较大字段存储在自己的表中可以通过其他方式提高工作流性能的一种用例是,当涉及并发和 DML 查询(例如s 和DELETE
s)锁定时。如果您的主表被大量读取并且大字段更新频率相同,则可能会遇到锁定争用,因为更新列通常会锁定整行。SELECT
通过将经常更改的较大字段分离到它们自己的表中,您可以消除对正在编辑的其余行数据的锁定(假设SELECT
查询当时没有利用这些较大的列)。如果您从不执行
select *
,则仅提取选定的字段,而未选定字段的大小影响非常小。当然,获取的速度仍然取决于其他因素,例如索引、触发器、硬件规格、互联网速度等。