使用LIMIT时如何获取总行数?

99

可能重复:
在使用偏移量和限制条件的MySQL查询中找到总结果数

我有一个非常复杂的SQL查询,返回的结果是分页的。问题是,在应用LIMIT之前获取总行数,我必须运行两次SQL查询。SQL查询非常复杂,我认为必须有更好的方法在不运行两次查询的情况下完成此操作。


15
很快您会收到使用SQL_CALC_FOUND_ROWS的建议,但事实是具有相同条件的COUNT(*)更有效。 - zerkms
你有检查过这个吗:https://dev59.com/b3E95IYBdhLWcg3wn_Vr - jtheman
1
请看这个链接:https://dev59.com/Fm025IYBdhLWcg3wkG57 - c.hill
@zerkms:为什么你不提供自己的答案呢? - static_rtti
2
@static_rtti 该注释包含足够的信息,不需要进一步阐述。 - zerkms
1个回答

123

幸运的是,自MySQL 4.0.0以来,您可以在查询中使用SQL_CALC_FOUND_ROWS选项,告诉MySQL忽略LIMIT子句并计算总行数。您仍需要执行第二个查询才能检索行计数,但它是一个简单的查询,不像检索数据的查询那样复杂。

使用方法非常简单。在主查询中,您需要在SELECT后添加SQL_CALC_FOUND_ROWS选项,在第二个查询中,您需要使用FOUND_ROWS()函数获取总行数。查询如下所示:

SELECT SQL_CALC_FOUND_ROWS name, email FROM users WHERE name LIKE 'a%' LIMIT 10;

SELECT FOUND_ROWS();

唯一的限制是必须立即在第一个查询之后调用第二个查询,因为SQL_CALC_FOUND_ROWS不会在任何地方保存行数。尽管此解决方案也需要两个查询,但速度要快得多,因为您只执行主查询一次。您可以在MySQL文档中了解有关SQL_CALC_FOUND_ROWS和FOUND_ROWS()的更多信息。
编辑:您应该注意,在大多数情况下,运行两次查询实际上比SQL_CALC_FOUND_ROWS更快。请参见here 编辑2019:
引用: SQL_CALC_FOUND_ROWS查询修饰符和相应的FOUND_ROWS()函数已从MySQL 8.0.17起停用,并将在未来的MySQL版本中删除。

https://dev.mysql.com/doc/refman/8.0/en/information-functions.html#function_found-rows

建议使用COUNT代替

SELECT * FROM tbl_name WHERE id > 100 LIMIT 10;
SELECT COUNT(*) WHERE id > 100;

4
据我理解,SQL_CALC_FOUND_ROWS 比不带 limit 的另一个查询要慢: http://www.percona.com/blog/2007/08/28/to-sql_calc_found_rows-or-not-to-sql_calc_found_rows/而且它不适用于子查询。 - Dariux
6
在我的情况下,SQL_CALC_FOUND_ROWS 绝对 不会 更慢,因为我使用的是一些复杂查询,需要花费 2 到 10 秒钟的时间。非常感谢,这很有帮助! - But those new buttons though..
4
这里是否存在并发问题?如果在你的SQL_CALC_FOUND_ROWS和FOUND_ROWS()之间有另一个人运行了另一个SQL_CALC_FOUND_ROWS会怎样呢?我正在使用[node.js MySQL插件](https://github.com/mysqljs/mysql),它允许多个查询语句,但我不确定这些子句是否在一个事务中执行。 - zipper
如果您只是将SQL_CALC_FOUND_ROWS()作为虚拟行与查询联合,那么这样做是否可以解决@zipper提到的并发问题呢? - zmippie
COUNT 的问题在于:https://github.com/sequelize/sequelize/issues/11692,当有多个 JOINS 时,计数可能不会返回预期结果。 - Yanick Rochon

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接