MySQL 中的解耦表提高了多少性能?

How much does decoupling tables in MySQL improve performance?

我正在设计数据库以在 MySQL 中存储一些博文。我最近 运行 浏览了这个 answer 它建议当你有:

  1. A table 将被定期查询(例如博客文章列表),但是
  2. 其中的一列 table 包含大量不会定期访问的数据(博客内容)

然后,如果您将内容存储在单独的 table 中,性能会更好,因此当您生成列表时,速度会更快。

CREATE TABLE article (
    id INT(10) UNSIGNED,
    title VARCHAR(40),
    author_id INT(10) UNIGNED,
    created DATETIME,
    modified DATETIME
);

CREATE TABLE article_text (
    id INT(10) UNSIGNED,
    body TEXT
);

即使列不是查询的一部分,这是否会影响性能:

SELECT id, title FROM article WHERE author_id=33 ORDER BY created DESC LIMIT 5

它会在多大程度上成为性能问题? (几百、几千?几百万?)

对你所有的问题都是肯定的。

"Vertical partitioning"(构建 "parallel table")在并不总是需要 TEXT(或 BLOB 等)时很有用。

当您不需要 TEXT 时,它的性能会更好,因为 table。

当您确实需要 TEXT 时,您可能只会获取一行(或很少的几行),因此 JOIN 到额外的 table 中的开销并不明显。

我有两个数据库,每个数据库有 20 万行,就这样拆分。两者都缩放得很好。我希望数百万甚至数十亿都没有问题。 (好吧,"billions" 有很多问题,但垂直分区是解决方案之一。)

您的示例 SELECT 需要 'compound' `INDEX(author_id, created) 才能扩展。但这与垂直分区无关。

在 MySQL 5.5 及更高版本中,InnoDB 存储引擎支持 Barracuda file format。为了使用 InnoDB 的 Barracuda 文件格式,你必须使用 file-per-table tablespace,或者使用通用的 table space (单文件 "system" InnoDB tablespace 不支持 Barracuda)。

在 Barracuda(羚羊)之前,MySQL always stored at least the first 768 bytes of a TEXT column in the clustered (primary key) index。在这种情况下,即使没有引用 TEXT 列,也会增加聚集索引(叶节点)中每一行的大小。这减慢了 table 对其他非 TEXT 列的扫描速度,因为每页适合的页面较少(平均要扫描更多页面以找到您要查找的内容),但在扫描 TEXT 列(第一个768 字节)。您是否经常进行 table 扫描?希望您能够使用索引来避免 table 扫描。

索引是 b-trees 并且键搜索在内部节点完成,其中只包含键。对于聚簇索引,那只是主键,所以聚簇索引搜索不受叶节点中数据量的影响(但受主键大小影响)。

对于 InnoDB 的 Barracuda 文件系统,整个 TEXT 列存储在溢出页中(可以压缩)。它的任何部分都不存储在聚集索引(叶节点)中。因此,如果您使用的是 Barracuda 文件系统,让 MySQL 为您进行分离,并将 TEXT 列放在相同的 table 中。在这种情况下,您没有任何收获,因为 MYSQL 已经将 TEXT 列放在其他地方并且不会影响扫描非 TEXT 列。

如果您正在使用 Antelope,如果您经常扫描非 TEXT 列(无论如何都应该避免),并且您很少引用 TEXT 列,则可以考虑拆分它。将其拆分为两个 tables,要读取整个记录,您现在必须在两个聚簇索引上进行搜索,这是一个的两倍。

我还可以看到想要在 MySQL 的 InnoDB 缓冲区 space 的 RAM 有限的系统上将其与 Antelope 拆分,并且您很少引用 TEXT 列。包含非 TEXT 列的叶节点如果较小,则更有可能保留在内存中。