暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

小白学习MySQL - “投机取巧”统计表的记录数

450

同事提了个统计需求,MySQL某个库60%的表都有个isdel字段(char(1)),值是0或1,现在要检索该数据库所有存在isdel字段且isdel=‘0’的表的记录数,举个例子,执行如下的count操作,

select count(*from test where isdel = '0';


但是库中有上千张表,一张张地拼,不符合程序猿的风格。


开始考虑的,是打算通过information_schema的tables中有个table_rows字段,显示表的行数,

select table_name, table_rows 
from information_schema.tables
 where table_schema='test';


但是从官方文档的介绍,MyISAM存储引擎存储的是精确值,但是对其他引擎,例如InnoDB,这个值就是不准确的了,有可能和实际的相差40%-50%,针对这种场景,应该用count(*),得到准确的值。而且他特意指出,InnoDB存储引擎的表,这个值仅仅是SQL优化器优化过程中用到的一个“粗略”预估的值,

https://dev.mysql.com/doc/refman/5.7/en/information-schema-tables-table.html


穿插一句,Oracle中,我们知道,dba/all/user_tables视图的num_rows字段表示这张表的记录数,和上述含义相同,但是这个信息,只有当统计信息更新的时候,才会更新,而统计信息的更新除了手动调用dbms_stats,另外就是等每天凌晨的定时任务调用了,但是定时任务执行的时候,不是所有表都会采集,而是判断如果该表执行过truncate,或者增删改数据量超过10%,才触发统计信息的更新操作,10%的量就通过dba_tab_modifications(数据字典基表是mon_mods$、mon_mods_all$,DML操作记录到mon_mods$,然后merge到mon_mods_all$)来统计的,他会记录数据库表的DML操作,包括insert、delete、update。因此dba/all/user_tables视图的num_rows的值不是实时准确的。


针对上述场景,这些表是InnoDB,因此只能通过count(*),得到统计值。


有什么更简单的操作,能够不拼接这几千张表,但可以得到他们的统计值?


参考了这位兄弟的文章,

https://blog.csdn.net/weixin_43655401/article/details/93973023


这个统计,包括这几个步骤,

(1) 找到所有包含isdel字段且isdel='0'的表。

(2) 依次执行count(*),统计每张表的记录数。

(3) 将(2)中得到的表名和记录数,存储到另外一张表中,作为检索用途。


我们按照倒序,依次操作下,

1. 创建一张统计表,除了id、insert_time外,tablename存储表名称,total存储该表总量,

create table table_count(
id int auto_increment,
tablename varchar(255),
total int,
insert_time timestamp,
primary key(id)
 );


2. 创建存储过程getDataByTableName,

(1) 入参是个表名,拼接的SQL是select count(*),加上这个入参,再加上条件where isdel = '0',将SQL执行结果,就是count(*)存入变量num。

(2) 如果(1)的num>0,则将表名、记录数、插入时间,存入table_count表。

delimiter $$
create procedure getDataByTableName(in tblName VARCHAR(255))
BEGIN
DECLARE num INT;
  SET @STMT =CONCAT("SELECT COUNT(*) FROM ", tblName ," WHERE isdel = '0' INTO @num;");
PREPARE STMT FROM @STMT;
EXECUTE STMT;
  IF(@num>0) THEN
INSERT INTO table_count(tablename, total, insert_time) VALUES (tblName, @num, now());
END IF;
end$$
delimiter ;


3. 创建存储过程process,

(1) 通过检索information_schema的columns视图,找到数据库test下存在列名叫isdel的表名,放入游标。

(2) 遍历游标,依次调用步骤2创建的存储过程。

delimiter $$
create procedure process()
BEGIN
DECLARE done BOOLEAN DEFAULT 0;
DECLARE tname VARCHAR (255);
DECLARE cur CURSOR
FOR
SELECT TABLE_NAME FROM information_schema.COLUMNS
WHERE COLUMN_NAME = 'isdel' AND TABLE_SCHEMA='test';
DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done=1;
OPEN cur;
     repeat FETCH cur INTO tname;
      call getDataByTableName(tname);
UNTIL done END repeat;
CLOSE cur;
end$$
delimiter ;


4. 执行存储过程process,

call process();


5. 检索table_count,此时表中记录,就是所有isdel='0',且count(*)>0的表名和对应的记录数了,

select * from table_count;


其实整个过程,就是我们惯性思维能考虑到的,只是要通过存储过程等技术进行封装,MySQL存储过程的语法,确实不太熟悉,借此学习一下。



小白学习MySQL,

小白学习MySQL - 一次慢SQL的定位

小白学习MySQL - TIMESTAMP类型字段非空和默认值属性的影响

小白学习MySQL - 聊聊数据备份的重要性

小白学习MySQL - InnoDB支持optimize table?

小白学习MySQL - table_open_cache的作用

小白学习MySQL - 表空间碎片整理方法

小白学习MySQL - 大小写敏感问题解惑

小白学习MySQL - only_full_group_by的校验规则

小白学习MySQL - max_allowed_packet

小白学习MySQL - mysqldump保证数据一致性的参数差异

小白学习MySQL - 查询会锁表?

小白学习MySQL - 索引键长度限制的问题

小白学习MySQL - MySQL会不会受到“高水位”的影响?

小白学习MySQL - 数据库软件和初始化安装

小白学习MySQL - 闲聊聊


近期更新的文章:

TimesTen In-Memory Database

小白学习MySQL - 一次慢SQL的定位

国足出现概率科普贴

GitHub的Watch、Star、Fork科普贴

Java的几个List集合操作


文章分类和索引:

《公众号800篇文章分类和索引

文章转载自bisal的个人杂货铺,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论