MySQL:计算行数的最快方法

时间:2011-02-20 21:59:14

标签: mysql performance

在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()

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

14 个答案:

答案 0 :(得分:117)

当你COUNT(*)计入列索引时,它将是最好的结果。带有 MyISAM 引擎的Mysql实际上存储行数,每次尝试计算所有行时都不计算所有行。 (基于主键的列)

使用PHP计算行不是很聪明,因为你必须将数据从mysql发送到php。为什么在mysql端实现相同的目的呢?

如果COUNT(*)速度很慢,您应该对查询运行EXPLAIN,并检查是否真正使用了索引,以及它们应该添加到何处。


以下不是最快的方式,但有一种情况,COUNT(*)并不适合 - 当您开始对结果进行分组时,您可能遇到问题,其中{ {1}}并不真正计算所有行。

解决方案是COUNT。这通常在您选择行时使用,但仍需要知道总行数(例如,用于分页)。 选择数据行时,只需在SELECT:

之后附加SQL_CALC_FOUND_ROWS关键字
SQL_CALC_FOUND_ROWS

选择了所需的行后,您可以通过以下单个查询获取计数:

SELECT SQL_CALC_FOUND_ROWS [needed fields or *] FROM table LIMIT 20 OFFSET 0;
必须在数据选择查询后立即调用

SELECT FOUND_ROWS();


总之,一切都归结为你拥有多少条目以及WHERE语句中的条目。当有很多行(数万,数百万及以上)时,你应该注意如何使用索引。

答案 1 :(得分:45)

在与我的队友交谈后,里卡多告诉我们,更快的方法是:

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

您可以在mysqlperformanceblog

找到完整的讨论

答案 2 :(得分:31)

很棒的问题,很棒的答案。如果有人正在阅读此页面并错过该部分,则可以快速回复结果:

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

答案 3 :(得分:13)

我一直都明白,下面会给我最快的响应时间。

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

答案 4 :(得分:13)

此查询(类似于bayuah发布的内容)显示了数据库中所有表计数的一个很好的摘要: (我强烈推荐的stored procedure by 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 |

答案 5 :(得分:6)

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

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

这通常不比使用COUNT更快,尽管人们可能认为情况正好相反,因为它在内部进行计算并且不会将数据发送回用户,因此怀疑性能提升。 / p>

执行这两个查询有助于获取总计,但不是特别适合使用WHERE子句。

答案 6 :(得分:5)

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

试验次数:    10 * 1000次查询

结果:    COUNT(*)更快7%

查看图表:benchmarkgraph

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

答案 7 :(得分:2)

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

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

答案 8 :(得分:1)

也许你可能想考虑做SELECT max(Id) - min(Id) + 1。这仅在您的ID是顺序的并且不删除行时才有效。然而它非常快。

答案 9 :(得分:1)

试试这个:

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

答案 10 :(得分:1)

我为德国政府处理了表格,有时有6000万条记录。

我们需要多次知道总行数。

因此我们数据库程序员决定在每个表中记录一个记录总存储记录号的记录。我们更新了这个数字,具体取决于INSERT或DELETE行。

我们尝试了所有其他方式。这是迄今为止最快的方式。

答案 11 :(得分:0)

EXPLAIN SELECT id FROM ....为我做了诀窍。我可以在结果的rows列下看到行数。

答案 12 :(得分:0)

对主键带有where条件的count(*)语句对我来说,行计数要快得多,从而避免了全表扫描。

template<typename T> struct DataOp: virtual Data<T> {
    virtual T value() { return this->data(); }
};

对我来说,这要快得多

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

答案 13 :(得分:0)

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

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

在我的基准测试中:0.448s

enter image description here

此查询需要4.835秒

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

enter image description here

计数*需要25.675s

SELECT count(*) FROM `orders`;

enter image description here