Mysql SQL_CALC_FOUND_ROWS 和分页

Posted

技术标签:

【中文标题】Mysql SQL_CALC_FOUND_ROWS 和分页【英文标题】:Mysql SQL_CALC_FOUND_ROWS and pagination 【发布时间】:2011-06-13 13:08:23 【问题描述】:

所以我有一个包含 500 万行多一点的表。当我使用 SQL_CALC_FOUND_ROWS 时,查询会永远挂起。当我把它拿出来时,查询会在一秒钟内执行 LIMIT ,25。我的问题是出于分页原因,是否有替代方法来获取总行数?

【问题讨论】:

【参考方案1】:

SQL_CALC_FOUND_ROWS 强制 mysql 扫描所有匹配的行,即使它们永远不会被获取。在内部,它相当于在没有 LIMIT 子句的情况下执行相同的查询。

如果您通过 WHERE 进行的过滤不是太疯狂,您可以计算并缓存各种类型的过滤器以节省 calc_found_rows 施加的全扫描负载。对于大多数可能的 where 子句,基本上运行“select count(*) from ... where ....”。

否则,您可以采用 Google 的方式,只是吐出一些偶尔与现实无关的页码(您知道,您会看到“Gooooooooooooogle”,进入第 3 页,然后突然用完结果)。

【讨论】:

是的,有些结果会返回超过一百万条记录,因此查询挂起的原因是有道理的。好吧,我想它应该只是指向下一页或上一页的链接,但不要在允许您跳到不同页面的地方进行分页。如果有超过一百万的退货,我认为他们不会在意转到第 10k 页。 @Marc,我知道这是一个老问题,但我发现自己面临的问题是是使用 SQL_CALC_FOUND_ROWS 还是从我的查询中删除 LIMIT 子句。从您的回答来看,您似乎是在说这些应该执行相同的操作。这是一个安全的假设,还是比这更复杂?谢谢。 有点复杂。虽然 calc_rows 确实强制 mysql 对所有行进行“位置”匹配,但它实际上并不需要检索整行,因此不必准备/获取将被丢弃的数据可以节省一些费用。对于非常大的记录(很多列)和/或很多行是有意义的。在较小的设备上,节省的费用不会那么明显,但我不知道切换点在哪里。【参考方案2】:

详细谈谈实现谷歌风格pagination using MySQL

【讨论】:

【参考方案3】:

您应该根据情况在 COUNT(*) 和 SQL_CALC_FOUND_ROWS 之间进行选择。如果您的查询搜索条件使用索引中的行 - 使用 COUNT(*)。在这种情况下,Mysql 将仅从索引中“读取”而不接触表中的实际数据,而 SQL_CALC_FOUND_ROWS 方法将从磁盘加载行,这在海量表上可能是昂贵且耗时的。

this article @mysqlperformanceblog 中有关此主题的更多信息。

【讨论】:

"如果您的查询搜索条件使用不在索引中的行 - 添加索引" 你说的那篇文章是2007年的,说真的,5年后你还引用它? MySQL 发生了很多变化。

以上是关于Mysql SQL_CALC_FOUND_ROWS 和分页的主要内容,如果未能解决你的问题,请参考以下文章

MySQL中SQL_CALC_FOUND_ROWS的用法

SQL_CALC_FOUND_ROWS 在 mysql 中不起作用

黄聪:mysql的SQL_CALC_FOUND_ROWS 使用 类似count(*) 使用性能更高

使用limit查询的同时取得总的记录数:SQL_CALC_FOUND_ROWS和FOUND_ROWS()

mysql_query() 为 FALSE 但 mysql_error() 为空

SQL Server 中是不是有等效的 SQL_CALC_FOUND_ROWS?