SQL 查询的性能主要取决于 JOIN、WHERE 子句、GROUP BY 和 ORDER BY,而不是检索到的列。如果检索到的数据明显更多,这些数据可能必须通过网络才能由您的编程语言处理,这些列才会对查询的速度产生显着影响。这里不是这样。
简短回答:两种建议设置之间的性能差异可能非常小。
为了获得良好的速度,您的 post_id 列应该有一个(唯一的)索引。您没有按任何其他列进行选择、排序或分组,因此数据可以直接来自表格,这是一个非常快速的过程。
您在这里谈论的是“页面”,所以我猜这些将呈现给用户 - 您似乎不太可能希望在同一页面上向人类显示数千篇博客文章的表格,因此您的陈述中实际上可能确实有 ORDER BY 和/或 LIMIT 子句,而这些子句并未包含在您的问题中。
但是让我们更深入地了解一下整个事情。假设我们实际上是直接从硬盘读取大量 TEXT 列,我们不会达到驱动器的最大读取速度吗?只检索一个 VARCHAR(250) 会不会更快,尤其是因为它为您节省了额外的 LEFT() 调用?
我们可以很快得到 LEFT() 调用。字符串函数非常快——毕竟只是 CPU 切断了一些数据,这是一个非常快的过程。它们产生明显延迟的唯一时间是在 WHERE 子句、JOIN 等中使用它们时,但这并不是因为这些函数很慢,而是因为它们必须运行很多次(可能是数百万次)才能甚至会产生单行结果,甚至更多,因为这些用途通常会阻止数据库正确使用其索引。
所以最后归结为:MySQL 从数据库中读取表内容的速度有多快。而这又取决于您使用的存储引擎及其设置。 MySQL 可以使用许多存储引擎,包括(但不限于)InnoDB 和 MyISAM。这两个引擎都为大对象(如 TEXT 或 BLOB 列)提供不同的文件布局(但有趣的是,还有 VARCHAR)。如果 TEXT 列存储在与行的其余部分不同的页面中,则存储引擎必须为每一行检索两个页面。如果它与其余部分一起存储,它将只是一页。对于顺序处理,这可能是性能上的重大变化。
这里有一些背景阅读:
长答案:这取决于:)
您必须在自己的硬件上进行大量基准测试才能真正确定哪种布局实际上更快。鉴于第二种设置在其附加列中引入了冗余,因此在大多数情况下它的性能可能会更差。当且仅当表结构允许较短的 VARCHAR 列适合磁盘上的同一页面,而较长的 TEXT 列适合另一个页面时,它将执行得更好。
编辑:有关 TEXT 列和性能的更多信息
对于 BLOB 和内存处理似乎存在一个常见的误解。相当多的页面(包括 StackOverflow 上的一些答案——我会尝试找到它们,并给出额外的评论)指出 MySQL 无法在内存中处理 TEXT 列(和所有其他 BLOB),因此总是性能猪。那不是真的。真正发生的事情是这样的:
如果您运行一个涉及 TEXT 列的查询并且该查询需要处理一个临时表,那么 MySQL 将不得不在磁盘上创建该临时表,而不是比在内存中,因为 MySQL 的 MEMORY 存储引擎无法处理 TEXT 列。见this related question。
MySQL documentation 声明了这一点(该段落对于从 3.2 到 5.6 的所有版本都是相同的):
查询结果中的 BLOB 或 TEXT 列实例
使用临时表处理会导致服务器在
磁盘而不是内存,因为 MEMORY 存储引擎不
支持这些数据类型(参见第 8.4.3.3 节,“MySQL 如何使用
内部临时表”)。使用磁盘会导致性能损失,
因此,只有在查询结果中包含 BLOB 或 TEXT 列时
真的需要。例如,避免使用 SELECT *,它选择所有
列。
这是最后一句话让人们感到困惑 - 因为那只是一个坏例子。一个简单的SELECT *不会受到这个性能问题的影响,因为它不会使用临时表。例如,如果相同的选择由非索引列排序,则 将 必须使用临时表并且将受到此问题的影响。在 MySQL 中使用EXPLAIN 命令来确定查询是否需要临时表。
顺便说一句:这些都不会影响缓存。 TEXT 列可以像其他任何内容一样被缓存。即使查询需要一个临时表并且必须存储在磁盘上,如果系统有资源这样做,结果仍然可以缓存,并且缓存不会失效。在这方面,TEXT 列与其他任何内容一样。
编辑 2:更多关于 TEXT 列和内存要求...
MySQL 使用存储引擎从磁盘检索记录。然后它将缓冲结果并按顺序将它们交给客户端。下面假设这个缓冲区最终在内存中而不是在磁盘上(原因见上文)
对于 TEXT 列(和其他 BLOB),MySQL 将缓冲一个指向实际 BLOB 的指针。这样的指针仅使用几个字节的内存,但需要在将行交给客户端时从磁盘中检索实际的 TEXT 内容。
对于 VARCHAR 列(以及除 BLOB 之外的所有其他列),MySQL 将缓冲实际数据。这通常会使用更多内存,因为您的大部分文本将不仅仅是几个字节。
对于计算列,MySQL 也会缓冲实际数据,就像使用 VARCHAR 一样。
对此有几点注意事项:从技术上讲,BLOB 在移交给客户端时也会被缓冲,但一次只能缓冲一个 - 对于大型 BLOB 可能不是全部。由于此缓冲区在每一行之后被释放,因此不会产生任何重大影响。此外,如果 BLOB 实际上与行的其余部分存储在同一页中,则它可能最终被视为 VARCHAR。老实说,我从未要求在单个查询中返回 很多 BLOB,所以我从未尝试过。
现在让我们实际回答(现已编辑的)问题:
第 1 页。用户概述和简短的博客文章 sn-ps。
您的选择几乎就是这些查询
SELECT userid, post_title, LEFT(post_description, 250) FROM `table_method_1` <-- calculated based on a VARCHAR column
SELECT userid, post_title, LEFT(post_description, 250) FROM `table_method_2` <-- calculated based on the TEXT column
SELECT userid, post_title, post_brief FROM `table_method_2` <-- precalculated VARCHAR column
SELECT userid, post_title, post_description FROM `table_method_2` <-- return the full text, let the client produce the snippet
前三个的内存需求相同。第四个查询将需要 less 内存(TEXT 列将作为指针缓冲),但 更多 流量到客户端。由于流量通常通过网络传输(在性能方面很昂贵),因此这往往比其他查询慢 - 但您的里程可能会有所不同。 TEXT 列上的 LEFT() 函数可以通过告诉存储引擎使用内联表格布局来加速,但这将取决于所存储文本的平均长度。
第 2 页。一篇博文
SELECT userid, post_title, post_description FROM `table_method_1` WHERE post_id=... <-- returns a VARCHAR
SELECT userid, post_title, post_description FROM `table_method_2` WHERE post_id=... <-- returns a TEXT
开始时内存要求很低,因为只会缓冲一行。由于上述原因,第二个将需要稍微少一点的内存来缓冲行,但需要一些额外的内存来缓冲单个 BLOB。
无论哪种情况,我很确定您不会关心仅返回单行的 select 的内存要求,所以这并不重要。
总结
如果您有任意长度的文本(或任何需要超过几千字节的文本),您应该使用 TEXT 列。这就是他们的目的。 MySQL 处理这些列的方式大部分时间都是有益的。
日常使用只需要记住两件事:
- 如果您实际上不需要它们,请避免选择 TEXT 列、BLOB 列和所有其他可能包含大量数据的列(是的,包括 VARCHAR(10000))。当您只需要几个值时,“SELECT * FROM whatever”的习惯会给数据库带来很多不必要的压力。
- 当您正在选择 TEXT 列或其他 BLOB 时,请确保选择不使用临时表。如有疑问,请使用
EXPLAIN 语法。
当您遵守这些规则时,您应该会从 MySQL 获得相当不错的性能。如果您需要进一步优化,则必须查看更精细的细节。这将包括存储引擎和相应的表格布局、有关实际数据的统计信息以及有关所涉及硬件的知识。根据我的经验,我通常可以摆脱对性能的贪婪,而无需深入挖掘。