当您限制通常在分页中使用的SQL查询返回的行数时,有两种方法可以确定记录总数:
SQL_CALC_FOUND_ROWS
在原始文件中包含该选项SELECT
,然后通过运行获取总行数SELECT FOUND_ROWS()
:
SELECT SQL_CALC_FOUND_ROWS * FROM table WHERE id > 100 LIMIT 10; SELECT FOUND_ROWS();
正常运行查询,然后通过运行获取总行数 SELECT COUNT(*)
SELECT * FROM table WHERE id > 100 LIMIT 10; SELECT COUNT(*) FROM table WHERE id > 100;
哪种方法最好/最快?
这取决于.请参阅有关此主题的MySQL性能博客文章:http: //www.mysqlperformanceblog.com/2007/08/28/to-sql_calc_found_rows-or-not-to-sql_calc_found_rows/
只是一个简短的总结:彼得说这取决于你的指数和其他因素.该帖子的许多评论似乎都说SQL_CALC_FOUND_ROWS几乎总是比运行两个查询慢 - 有时慢10倍.
在选择"最佳"方法时,比速度更重要的考虑因素可能是代码的可维护性和正确性.如果是这样,SQL_CALC_FOUND_ROWS是首选,因为您只需要维护一个查询.使用单个查询完全排除了主查询和计数查询之间存在细微差别的可能性,这可能导致COUNT不准确.
根据以下文章:https://www.percona.com/blog/2007/08/28/to-sql_calc_found_rows-or-not-to-sql_calc_found_rows/
如果你的where子句有一个INDEX(如果在你的情况下id被索引),那么最好不要使用SQL_CALC_FOUND_ROWS而是使用2个查询,但是如果你没有索引你在where子句中放入的内容(在您的情况下为id)然后使用SQL_CALC_FOUND_ROWS更有效.
从SQL_CALC_FOUND_ROWS
8.0.17版开始,MySQL已开始弃用该功能。
因此,它总是优先考虑与执行查询LIMIT
,然后用第二个查询COUNT(*)
,并没有LIMIT
确定是否有其他行。
从文档:
从MySQL 8.0.17开始,SQL_CALC_FOUND_ROWS查询修饰符和随附的FOUND_ROWS()函数已弃用,并将在以后的MySQL版本中删除。
COUNT(*)受到某些优化。SQL_CALC_FOUND_ROWS导致一些优化被禁用。
请改用以下查询:
SELECT * FROM tbl_name WHERE id > 100 LIMIT 10; SELECT COUNT(*) WHERE id > 100;
另外,SQL_CALC_FOUND_ROWS
如MySQL WL#12615中所述,通常会遇到更多问题:
SQL_CALC_FOUND_ROWS有很多问题。首先,它很慢。通常,使用LIMIT运行查询,然后对同一查询使用单独的SELECT COUNT()运行会比较便宜,因为COUNT()可以利用在搜索整个结果集(例如文件排序)时无法完成的优化可以跳过COUNT(*),而对于CALC_FOUND_ROWS,我们必须禁用一些文件排序优化以保证正确的结果)
更重要的是,它在许多情况下的语义非常不清楚。特别是,当一个查询具有多个查询块(例如,使用UNION)时,根本无法在生成有效查询的同时计算“必须拥有”的行数。随着迭代器执行器朝着这类查询的方向发展,真正很难尝试保留相同的语义。此外,如果查询中有多个LIMIT(例如,对于派生表),则不一定清楚SQL_CALC_FOUND_ROWS应该指向哪个。因此,与之前相比,这种非平凡的查询在迭代器执行器中必然会获得不同的语义。
最后,大多数使用SQL_CALC_FOUND_ROWS似乎有用的用例应该仅通过除LIMIT / OFFSET之外的其他机制解决。例如,电话簿应按字母(在UX和索引使用方面)而不是记录号进行分页。讨论越来越按日期(再次允许使用索引)而不是按帖子编号分页进行无限滚动。等等。
恕我直言,2查询的原因
SELECT * FROM count_test WHERE b = 666 ORDER BY c LIMIT 5; SELECT count(*) FROM count_test WHERE b = 666;
比使用SQL_CALC_FOUND_ROWS更快
SELECT SQL_CALC_FOUND_ROWS * FROM count_test WHERE b = 555 ORDER BY c LIMIT 5;
必须被视为一个特例.
事实上,它取决于WHERE子句的选择性与隐含的ORDER + LIMIT的选择性相比.
正如Arvids在评论中所说(http://www.mysqlperformanceblog.com/2007/08/28/to-sql_calc_found_rows-or-not-to-sql_calc_found_rows/#comment-1174394),EXPLAIN使用与否的事实,一个临时表,应该是了解SCFR是否更快的良好基础.
但是,正如我添加的那样(http://www.mysqlperformanceblog.com/2007/08/28/to-sql_calc_found_rows-or-not-to-sql_calc_found_rows/#comment-8166482),结果确实取决于具体情况.对于特定的分页符,您可以得出结论"对于3个首页,使用2个查询; 对于以下页面,使用SCFR"!
删除一些不必要的SQL,然后COUNT(*)
比删除速度更快SQL_CALC_FOUND_ROWS
。例:
SELECT Person.Id, Person.Name, Job.Description, Card.Number FROM Person JOIN Job ON Job.Id = Person.Job_Id LEFT JOIN Card ON Card.Person_Id = Person.Id WHERE Job.Name = 'WEB Developer' ORDER BY Person.Name
然后计算没有不必要的部分:
SELECT COUNT(*) FROM Person JOIN Job ON Job.Id = Person.Job_Id WHERE Job.Name = 'WEB Developer'