mysql在大表中计数行的性能

mysql在大表中计数行的性能,mysql,bigdata,Mysql,Bigdata,这个相当明显的问题几乎没有(找不到)可靠的答案 我从200万行的表中进行简单的选择 select count(id) as total from big_table 我在任何一台机器上尝试这个查询,通常至少需要5秒钟才能完成。这对于实时查询是不可接受的 我需要获取的行的精确值的原因是为了以后进行精确的统计计算 遗憾的是,使用最后一个自动增量值不是一个选项,因为行也会定期删除。您有索引吗 ALTER TABLE big_table ADD INDEX id 您可以检查并尝试添加此是否有索引 A

这个相当明显的问题几乎没有(找不到)可靠的答案

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

select count(id) as total from big_table
我在任何一台机器上尝试这个查询,通常至少需要5秒钟才能完成。这对于实时查询是不可接受的

我需要获取的行的精确值的原因是为了以后进行精确的统计计算

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

您有索引吗

ALTER TABLE big_table ADD INDEX id
您可以检查并尝试添加此

是否有索引

ALTER TABLE big_table ADD INDEX id

您可以检查并尝试添加此

在InnoDB引擎上运行时,它确实可能会很慢。如第3条要点所述:

InnoDBInnoDB不在表中保留行的内部计数,因为并发事务可能同时“看到”不同数量的行。因此,SELECT COUNT(*)语句只对当前事务可见的行进行计数

有关InnoDB如何处理SELECT COUNT(*)语句的信息,请参阅第12.20.1节“聚合函数说明”中的COUNT()说明

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

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;
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);
您可以在这里看到,您应该在构建部分更改
insert
/
delete
语句,以查看对以下内容的影响:

select rec_count from big_table_count;
您可以对多个表进行扩展,或者为每个表创建这样的表,或者在上面的计数器表中为每个表保留一行。然后,它将被一列“table_name”键入

改进并发性 如果有许多并发会话插入或删除记录,则上述方法确实会产生影响,因为它们需要等待对方完成计数器的更新

解决方案是不让触发器更新同一条记录,而是让触发器插入一条新记录,如下所示:

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;
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;

在InnoDB引擎上运行时,它确实会很慢。如第3条要点所述:

InnoDBInnoDB不在表中保留行的内部计数,因为并发事务可能同时“看到”不同数量的行。因此,SELECT COUNT(*)语句只对当前事务可见的行进行计数

有关InnoDB如何处理SELECT COUNT(*)语句的信息,请参阅第12.20.1节“聚合函数说明”中的COUNT()说明

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

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;
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);
您可以在这里看到,您应该在构建部分更改
insert
/
delete
语句,以查看对以下内容的影响:

select rec_count from big_table_count;
您可以对多个表进行扩展,或者为每个表创建这样的表,或者在上面的计数器表中为每个表保留一行。然后,它将被一列“table_name”键入

改进并发性 如果有许多并发会话插入或删除记录,则上述方法确实会产生影响,因为它们需要等待对方完成计数器的更新

解决方案是不让触发器更新同一条记录,而是让触发器插入一条新记录,如下所示:

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;
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;

id设置为主键。。。我应该添加索引吗?id设置为主键。。。我应该添加索引吗?看不到与mysqli和/或PHP的关系。编辑您的问题以添加相关信息或删除标记。他有一个公认的答案。不走运?@Alfabravo似乎最佳做法是将值存储在单独的表中,并添加更新该值的触发器(InnoDB案例)。看不到与mysqli和/或PHP的关系。编辑您的问题以添加相关信息或删除标记。他有一个公认的答案。不走运?@Alfabravo似乎最佳做法是将值存储在单独的表中,并添加更新该值的触发器(InnoDB案例)。