首选解决方案
首先,found_rows() 函数不可移植(它是一个 MySQL 扩展)并且将被删除。正如用户@Zveddochka 指出的那样,它已经在 MySQL 8.0.17 中被弃用。
但更重要的是,事实证明,如果您使用正确的索引,那么运行两个查询实际上会更快。该SQL_CALC_FOUND_ROWS
指令是通过产生额外恢复成本的“虚拟扫描”实现的。当查询没有被索引时,这个成本将与 a 相同COUNT()
,因此运行两个查询将花费双倍 - 即,使用SQL_CALC_FOUND_ROWS
将使事情运行速度提高 50%。
但是当查询被正确索引时会发生什么?Percona 的人检查了它。事实证明,不仅COUNT()
速度非常快,因为它只访问元数据和索引,而且查询SQL_CALC_FOUND_ROWS
速度更快,因为它不会产生任何额外的成本;两个查询组合的成本低于增强的单个查询的成本:
SQL_CALC_FOUND_ROWS 的结果如下:对于每个 b 值,执行非缓存需要 20-100 秒,预热后需要 2-5 秒。这种差异可以通过这个查询所需的 I/O 来解释——mysql 访问这个查询可以在没有 LIMIT 子句的情况下产生的所有 10k 行。
结果如下:第一次运行此查询需要 0.01-0.11 秒,所有连续运行需要 0.00-0.02 秒。
因此,正如我们所见,SELECT+COUNT 的总时间(0.00-0.15 秒)远小于原始查询的执行时间(2-100 秒)。让我们来看看解释...
那么该怎么办?
// Run two queries ensuring they satisfy exactly the same conditions
$field1 = "Field1, Field2, blah blah blah";
$field2 = "COUNT(*) AS rows";
$where = "Field5 = 'X' AND Field6 = 'Y' AND blah blah";
$cntQuery = "SELECT {$field2} FROM {$joins} WHERE {$where}";
$rowQuery = "SELECT {$field1} FROM {$joins} WHERE {$where} LIMIT {$limit}";
现在第一个查询返回计数,第二个查询返回实际数据。
旧答案(仅对非索引表有用)
不要这样做。如果您发现答案的这一部分比上面的部分更适合您,这几乎肯定是一个信号,表明您的设置中的其他东西不是最佳的 - 很可能您没有正确使用索引,或者您需要更新您的MySQL 服务器,或运行数据库分析/优化以更新基数统计信息。
你可以,但我认为这将是一个性能杀手。
您最好的选择是使用SQL_CALC_FOUND_ROWS
MySQL 扩展并发出第二个查询以使用 FOUND_ROWS() 恢复全部行数。
SELECT SQL_CALC_FOUND_ROWS * FROM t WHERE t.nid <1000 LIMIT 10;
SELECT FOUND_ROWS();
参见例如http://www.arraystudio.com/as-workshop/mysql-get-total-number-of-rows-when-using-limit.html
或者您可以简单地运行不带LIMIT
子句的完整查询,并仅检索前十行。然后,您可以根据需要使用一个查询,并且还可以通过mysql_num_rows()
. 这并不理想,但对于大多数查询来说也不是那么灾难性。
但是,如果您最后这样做,请非常小心地关闭查询并释放其资源:我发现检索不到完整的结果集并忘记释放 rs 句柄是“元数据锁定”的一个突出原因。