前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >小白学习MySQL - “投机取巧”统计表的记录数

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

作者头像
bisal
发布2021-11-29 11:06:55
4.3K0
发布2021-11-29 11:06:55
举报
文章被收录于专栏:bisal的个人杂货铺

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

代码语言:javascript
复制
select count(*) from test where isdel = '0';

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

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

代码语言:javascript
复制
select table_name, table_rows 
  from information_schema.tables 
 where table_schema='test';

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

c3d7dd816efa89183f95c1a7008c1539.png
c3d7dd816efa89183f95c1a7008c1539.png

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存储该表总量,

代码语言:javascript
复制
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表。

代码语言:javascript
复制
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创建的存储过程。

代码语言:javascript
复制
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,

代码语言:javascript
复制
call process();

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

代码语言:javascript
复制
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 - 闲聊聊

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021/11/26 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
对象存储
对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档