mysql在大表中计数行的性能

时间:2015-12-29 13:27:11

标签: mysql bigdata

这个相当明显的问题很少(找不到)可靠的答案。

我从200万行的表格中进行简单的选择。

select count(id) as total from big_table

我尝试此查询的任何计算机通常至少需要5秒才能完成。这对于实时查询来说是不可接受的。

我需要获取行的精确值的原因是稍后进行精确的统计计算。

遗憾的是,使用上一个自动增量值不是一个选项,因为行也会定期删除。

2 个答案:

答案 0 :(得分:5)

在InnoDB引擎上运行时确实很慢。如section 14.5.7 of the MySQL 5.7 Reference Manual, “Restrictions on InnoDB Tables”中所述,第4点要点:

  

InnoDB 不保留表中的内部行数,因为并发事务可能会同时“看到”不同数量的行。要处理SELECT COUNT(*) FROM t语句, InnoDB 会扫描表的索引,如果索引不完全在缓冲池中,则需要一些时间。要快速计数,您必须使用自己创建的计数器表,并让应用程序根据插入和删除更新它。如果大概行数足够,则可以使用SHOW TABLE STATUS

建议的解决方案是计数器表。这是一个单独的表,其中包含一行和一列,具有当前记录计数。它可以通过触发器保持更新。像这样:

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”键入。

提高并发性

如果您有多个并发会话插入或删除记录,上述方法会产生影响,因为他们需要等待彼此完成计数器的更新。

解决方案是不让触发器更新相同的单个记录,而是让他们插入新记录,如下所示:

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;

答案 1 :(得分:-1)

你有索引吗?

ALTER TABLE big_table ADD INDEX id

您可以检查并尝试添加此