【问题标题】:Mysql SQL_CALC_FOUND_ROWS and paginationMysql SQL_CALC_FOUND_ROWS 和分页
【发布时间】:2026-02-03 22:25:01
【问题描述】:

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

【问题讨论】:

    标签: mysql pagination sql-calc-found-rows


    【解决方案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 发生了很多变化。