哪个最快? SELECT SQL_CALC_FOUND_ROWS FROM`table`或SELECT COUNT(*)

时间:2008-10-09 09:53:56

标签: mysql optimization

当您限制通常在分页中使用的SQL查询返回的行数时,有两种方法可以确定记录总数:

方法1

在原始SQL_CALC_FOUND_ROWS中加入SELECT选项,然后运行SELECT FOUND_ROWS()获取总行数:

SELECT SQL_CALC_FOUND_ROWS * FROM table WHERE id > 100 LIMIT 10;
SELECT FOUND_ROWS();  

方法2

正常运行查询,然后通过运行SELECT COUNT(*)

获取总行数
SELECT * FROM table WHERE id > 100 LIMIT 10;
SELECT COUNT(*) FROM table WHERE id > 100;  

哪种方法最好/最快?

7 个答案:

答案 0 :(得分:111)

这取决于。请参阅有关此主题的MySQL Performance Blog帖子:http://www.mysqlperformanceblog.com/2007/08/28/to-sql_calc_found_rows-or-not-to-sql_calc_found_rows/

只是一个简短的总结:彼得说这取决于你的指数和其他因素。该帖子的许多评论似乎都说SQL_CALC_FOUND_ROWS几乎总是比运行两个查询慢 - 有时慢10倍。

答案 1 :(得分:18)

在选择“最佳”方法时,比速度更重要的考虑因素可能是代码的可维护性和正确性。如果是这样,SQL_CALC_FOUND_ROWS是首选,因为您只需要维护一个查询。使用单个查询完全排除了主查询和计数查询之间存在细微差别的可能性,这可能会导致COUNT不准确。

答案 2 :(得分:13)

根据以下文章: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 会更有效。

答案 3 :(得分:8)

恕我直言,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“!

答案 4 :(得分:6)

删除一些不必要的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'

答案 5 :(得分:2)

从8.0.17版开始,MySQL已开始弃用SQL_CALC_FOUND_ROWS功能。

因此,总是首选,考虑使用LIMIT执行查询,然后考虑使用COUNT(*)和不使用LIMIT进行第二次查询以确定是否存在是其他行。

来自docs

  

SQL_CALC_FOUND_ROWS查询修饰符和随附的FOUND_ROWS()   自MySQL 8.0.17起不推荐使用此函数,并将在   将来的MySQL版本。

     

COUNT(*)受到某些优化。 SQL_CALC_FOUND_ROWS   导致某些优化被禁用。

     

改为使用以下查询:

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

答案 6 :(得分:1)

还有其他基准测试选项:

1。)。窗口函数将直接返回实际大小(在MariaDB中测试):

SELECT 
  `mytable`.*,
  COUNT(*) OVER() AS `total_count`
FROM `mytable`
ORDER BY `mycol`
LIMIT 10, 20

2。)开箱即用,大多数时候用户不需要知道表的 EXACT 大小,通常近似值就足够了

SELECT `TABLE_ROWS` AS `rows_approx`
FROM `INFORMATION_SCHEMA`.`TABLES`
WHERE `TABLE_SCHEMA` = DATABASE()
  AND `TABLE_TYPE` = "BASE TABLE"
  AND `TABLE_NAME` = ?