MySQL:计算行数的最快方法

Fra*_*anz 109 mysql performance

在MySQL中哪种方式计算多行应该更快?

这个:

SELECT COUNT(*) FROM ... WHERE ...
Run Code Online (Sandbox Code Playgroud)

或者,替代方案:

SELECT 1 FROM ... WHERE ...

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

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

Mār*_*dis 119

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

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

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


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

解决方案是SQL_CALC_FOUND_ROWS.这通常在您选择行时使用,但仍需要知道总行数(例如,用于分页).选择数据行时,只需SQL_CALC_FOUND_ROWS在SELECT后附加关键字:

SELECT SQL_CALC_FOUND_ROWS [needed fields or *] FROM table LIMIT 20 OFFSET 0;
Run Code Online (Sandbox Code Playgroud)

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

SELECT FOUND_ROWS();
Run Code Online (Sandbox Code Playgroud)

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


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

  • 更正:`MyISAM`存储行数.其他存储引擎如`InnoDB`**不会**存储行计数,*会每次计算所有行*. (13认同)
  • 引擎存储行数是无关紧要的.问题清楚地表明存在一个"WHERE"条款. (5认同)
  • FOUND_ROWS 和 SQL_CALC_FOUND_ROWS 已被弃用,并且不会在 MySQL 8.0.17 以上的版本中使用。http://dev.mysql.com/doc/refman/5.0/en/information-functions.html#function_found-rows (3认同)

Mag*_*Max 51

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

show table status like '<TABLE NAME>' \G
Run Code Online (Sandbox Code Playgroud)

但你必须记住结果可能不准确.

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

$ mysqlshow --status <DATABASE> <TABLE NAME>
Run Code Online (Sandbox Code Playgroud)

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

您可以在mysqlperformanceblog上找到完整的讨论

  • 对于InnoDB,这是一个近似值. (2认同)
  • 当需要粗略了解 count(*) 可能需要数小时的非常大的表中的行数时,知道这一点非常有用! (2认同)
  • 使用`SHOW TABLE STATUS`(或`information_schema`中的等效`SELECT`)很快,但它不处理`WHERE`子句.它对于MyISAM来说是精确的,但对InnoDB来说是不精确的(有时偏差2倍). (2认同)

Dan*_*vat 30

很棒的问题,很棒的答案.如果有人正在阅读此页面并错过该部分,这是一种快速回显结果的方法:

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

  • 为什么不"算数"?`id`在第一眼看上去很混乱. (7认同)
  • 从PHP 5.5.0开始,mysql_query是一个不推荐使用的函数. (4认同)

lep*_*epe 14

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

__CODE__YOURDBNAME__CODE__ ;

例:

__CODE__

  • 只是给读者的一个提示。这种方法非常快,但仅适用于可以处理近似行数的情况,因为在使用 InnoDB 的情况下,“information_schema”中存储的值与“SELECT count(*) FROM”返回的值不同。如果您需要严格值,请记住此方法仅对 MyISAM 表提供严格值。对于 InnoDB,行数是粗略的近似值。 (3认同)

ada*_*shr 13

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

SELECT COUNT(1) FROM ... WHERE ...
Run Code Online (Sandbox Code Playgroud)

  • @patrick - `SELECT 1 ...`将返回与`WHERE`和`LIMIT`一样多的行,并且它们都将为"1". (2认同)
  • @deep - 但如果您有“WHERE”子句,则不相关。而且,对于InnoDB来说,这只是一个估计。 (2认同)

Ale*_*kov 6

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

SELECT SQL_CALC_FOUND_ROWS * FROM table_name LIMIT 5;
SELECT FOUND_ROWS();
Run Code Online (Sandbox Code Playgroud)

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

执行这两个查询对于获取总计的分页是有利的,但对于使用WHERE子句则不是特别有用.

  • 实际上,这通常不比使用COUNT(*)快.请参阅http://stackoverflow.com/questions/186588/which-is-fastest-select-sql-calc-found-rows-from-table-or-select-count (3认同)
  • 使用此功能时应该非常小心.它的鲁莽使用曾使我们的整个生产环境停滞不前.它非常耗费资源,因此要小心使用. (2认同)

bay*_*uah 6

尝试这个:

SELECT
    table_rows "Rows Count"
FROM
    information_schema.tables
WHERE
    table_name="Table_Name"
AND
    table_schema="Database_Name";
Run Code Online (Sandbox Code Playgroud)


ssr*_*srp 6

EXPLAIN SELECT id FROM ....为我成功了。rows我可以看到结果列下的行数。


小智 5

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

试验次数:10*1000次查询

结果: COUNT(*)快7%

VIEW GRAPH:benchmarkgraph

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

  • 仅供参考,还有一种常见的方法来使用“COUNT(1)”进行计数,看到一些基准会很有趣...... (2认同)