这个相当明显的问题几乎没有(找不到任何)可靠的答案。
我从 200 万行的表中进行简单的选择。
select count(id) as total from big_table
我在任何机器上尝试此查询,通常至少需要 5 秒才能完成。这对于实时查询是 Not Acceptable 。
我需要获取行的精确值的原因是为了稍后进行精确的统计计算。
不幸的是,使用最后一个自动增量值不是一个选项,因为行也会定期删除。
最佳答案
在 InnoDB 引擎上运行时确实会很慢。如 section 14.24 of the MySQL 5.7 Reference Manual, “InnoDB Restrictions and Limitations” 中所述, 第三个要点:
InnoDB InnoDB does not keep an internal count of rows in a table because concurrent transactions might “see” different numbers of rows at the same time. Consequently, SELECT COUNT(*) statements only count rows visible to the current transaction.
For information about how InnoDB processes SELECT COUNT(*) statements, refer to the COUNT() description in Section 12.20.1, “Aggregate Function Descriptions”.
建议的解决方案是计数器表。这是一个单行一列的单独表格,包含当前记录数。它可以通过触发器保持更新。像这样:
create table big_table_count (rec_count int default 0);
-- one-shot initialisation:
insert into big_table_count select count(*) from big_table;
create trigger big_insert after insert on big_table
for each row
update big_table_count set rec_count = rec_count + 1;
create trigger big_delete after delete on big_table
for each row
update big_table_count set rec_count = rec_count - 1;
你可以在这里看到一个 fiddle ,您应该在构建部分更改 insert
/delete
语句以查看对以下方面的影响:
select rec_count from big_table_count;
您可以将此扩展到多个表,方法是为每个表创建一个这样的表,或者在上面的计数器表中为每个表保留一行。然后它将由 “table_name” 列作为键。
提高并发性
如果您有许多并发 session 插入或删除记录,上述方法确实会产生影响,因为它们需要等待彼此完成计数器的更新。
一个解决方案是不要让触发器更新同一条记录,而是让它们插入一条新记录,如下所示:
create trigger big_insert after insert on big_table
for each row
insert into big_table_count (rec_count) values (1);
create trigger big_delete after delete on big_table
for each row
insert into big_table_count (rec_count) values (-1);
然后获取计数的方法变为:
select sum(rec_count) from big_table_count;
然后,偶尔(例如每天)您应该重新初始化计数器表以使其较小:
truncate table big_table_count;
insert into big_table_count select count(*) from big_table;
关于mysql - mysql 计算大表中行的性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34512084/