MySQL: 计算行数的最快方法

在 MySQL 中,哪种计算行数的方法更快?

这个:

SELECT COUNT(*) FROM ... WHERE ...

或者,另一种选择:

SELECT 1 FROM ... WHERE ...


// and then count the results with a built-in function, e.g. in PHP mysql_num_rows()

人们可能会认为第一种方法应该更快,因为这显然是数据库领域,数据库引擎在内部确定这样的事情时应该比其他任何人都快。

240879 次浏览

我一直都知道下面的内容会给我最快的反应时间。

SELECT COUNT(1) FROM ... WHERE ...

当您使用 COUNT(*)时,它会接受计数列索引,因此这将是最好的结果。MySQL 与 MyISAM引擎实际上存储行计数,它不会计数所有行每次你尝试计数所有行。(基于主键的列)

使用 PHP 来计算行数并不明智,因为必须将数据从 MySQL 发送到 PHP。如果在 MySQL 方面也可以实现同样的功能,为什么还要这样做呢?

如果 COUNT(*)运行缓慢,则应该对查询运行 EXPLAIN,并检查是否真正使用了索引,以及应该在何处添加索引。


下面不是 最快的方法,但是有一种情况下,COUNT(*)并不真正适合-当您开始分组结果时,您可能会遇到一个问题,即 COUNT并不真正计算所有行。

解决方案是 SQL_CALC_FOUND_ROWS。这通常用于选择行但仍然需要知道总行数(例如,用于分页)的情况。 选择数据行时,只需在 SELECT 之后添加 SQL_CALC_FOUND_ROWS关键字:

SELECT SQL_CALC_FOUND_ROWS [needed fields or *] FROM table LIMIT 20 OFFSET 0;

在选择了所需的行之后,您可以通过这个单独的查询获得计数:

SELECT FOUND_ROWS();

必须在数据选择查询之后立即调用 FOUND_ROWS()


总之,一切实际上都取决于您拥有多少条目以及 WHERE 语句中包含什么。您真的应该注意如何使用索引,当有很多行(数万行、数百万行以上)时。

好问题,好答案。如果有人正在阅读这个页面而忽略了这一部分,这里有一个快速的方法来回应结果:

$counter = mysql_query("SELECT COUNT(*) AS id FROM table");
$num = mysql_fetch_array($counter);
$count = $num["id"];
echo("$count");

也许你可以考虑做一个 SELECT max(Id) - min(Id) + 1。这只有在您的 ID 是连续的且没有删除行的情况下才有效。然而,它是非常快的。

如果您需要得到整个结果集的计数,您可以采取以下方法:

SELECT SQL_CALC_FOUND_ROWS * FROM table_name LIMIT 5;
SELECT FOUND_ROWS();

这通常不会比使用 COUNT更快,尽管有人可能会认为情况正好相反,因为它在内部进行计算,不会将数据发送回用户,因此性能改进是可疑的。

执行这两个查询有利于分页以获取总计,但不利于使用 WHERE子句。

在和我的队友们谈过之后,里卡多告诉我们最快的方法是:

show table status like '<TABLE NAME>' \G

但你必须记住,结果可能并不准确。

您也可以从命令行使用它:

$ mysqlshow --status <DATABASE> <TABLE NAME>

更多信息: http://dev.mysql.com/doc/refman/5.7/en/show-table-status.html

你可以在 MysqlPerformance 博客找到一个完整的讨论

试试这个:

SELECT
table_rows "Rows Count"
FROM
information_schema.tables
WHERE
table_name="Table_Name"
AND
table_schema="Database_Name";

这个查询(类似于 Bayuah 发布的内容)显示了数据库中所有表计数的一个很好的总结: (我强烈推荐的简化版 存储过程由 Ivan Cachicatari)。

SELECT TABLE_NAME AS 'Table Name', TABLE_ROWS AS 'Rows' FROM information_schema.TABLES WHERE TABLES.TABLE_SCHEMA = '`YOURDBNAME`' AND TABLES.TABLE_TYPE = 'BASE TABLE';

例如:

+-----------------+---------+
| Table Name      | Rows    |
+-----------------+---------+
| some_table      |   10278 |
| other_table     |     995 |

我做了一些基准测试 来比较 COUNT(*)COUNT(id)的执行时间(id 是表索引的主键)。

试验次数: 10 * 1000次查询

结果: COUNT(*)比我们快7%

视图: 基准测试表

我的建议是使用: SELECT COUNT(*) FROM table

我为德国政府处理桌子,有时有6000万份记录。

我们需要知道总行数的许多倍。

因此,我们数据库程序员决定,在每个表中总是记录一条记录,其中总记录数存储在这条记录中。我们根据 INSERT 或 DELETE 行更新了这个数字。

我们试了所有其他方法,这是目前为止最快的方法。

EXPLAIN SELECT id FROM ....帮了我一个大忙,我可以看到结果的 rows列下面有多少行。

带有主键 where 条件的 count (*)语句可以更快地返回行数,从而避免了全表扫描。

SELECT COUNT(*) FROM ... WHERE <PRIMARY_KEY> IS NOT NULL;

这对我来说比

SELECT COUNT(*) FROM ...

这是能够获得最快结果的最佳查询。

SELECT SQL_CALC_FOUND_ROWS 1 FROM `orders`;
SELECT FOUND_ROWS();

在我的基准测试中: 0.448秒

enter image description here

此查询需要4.835 s

SELECT SQL_CALC_FOUND_ROWS * FROM `orders`;
SELECT FOUND_ROWS();

enter image description here

Count * 需要25.675秒

SELECT count(*) FROM `orders`;

enter image description here

如果你不需要超级精确的计数,那么你可以为当前会话设置一个较低的事务隔离。这样做:

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
SELECT count(*) FROM the_table WHERE ...;
COMMIT; /* close the transaction */

有一个匹配 WHERE条件的索引也很好。

它确实加快了大型 InnoDB 表的计数速度。我在一个大约有700M 行并且负载很重的表上检查了它,它工作正常。它将查询时间从451秒减少到2秒。

我的想法来自于这个答案: https://stackoverflow.com/a/918092/1743367