日常应用运维工作中,Dev或者db本身都需要统计表的行数,以此作为应用或者维护的一个信息参考。也许很多人会忽略select count(*) from table_name类似的sql对数据库性能的影响,可当你在慢日志平台看到执行了数千次,每次执行4秒左右的查询,你还会无动于衷吗?作为一个有担当敢于挑战的dba,你们应该勇于说no,我觉得类似的需求不可避免但不应该是影响数据库性能的因素,如果连这个都摆不平公司还能指望你干什么。经过几番深思总结,我根据查询的需求,分为模糊查询和精确查询,可以通过下面的三种方式来择优选择。下面测试是线上一个日志表,表大小在6个G左右。

  1、精确查询知晓表中数据行数,这个时候我们就要使用count()函数来统计表中行数的大小了。在innodb存储引擎中count(*)函数是先从内存中读取表中的数据到内存缓冲区,然后全表扫描获得记录行数的。但是这种方式过于简单、直接暴力,对于小表查询比较合适,对于频繁的大表查询就不适用了。尤其是在生产中表很大,且表除了聚集索引(主键索引)外,没有其他非聚集索引(二级索引)的时候,无疑是一种巨大的灾难。

mysql> select count(*) from operation_log;
+----------+
| count(*) |
+----------+
| 21049180 |
+----------+
1 row in set (10.92 sec) mysql> explain select count(*) from rule_ceshi.operation_log;
+----+-------------+---------------+-------+---------------+----------+---------+------+----------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------------+-------+---------------+----------+---------+------+----------+-------------+
| 1 | SIMPLE | operation_log | index | NULL | user_key | 194 | NULL | 20660338 | Using index |
+----+-------------+---------------+-------+---------------+----------+---------+------+----------+-------------+
1 row in set (0.00 sec) mysql> show index from rule_ceshi.operation_log;
+---------------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+---------------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| operation_log | 0 | PRIMARY | 1 | id | A | 20660338 | NULL | NULL | | BTREE | | |
| operation_log | 1 | user_key | 1 | user_key | A | 2951476 | NULL | NULL | | BTREE | | |
+---------------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
2 rows in set (0.00 sec) mysql> drop index user_key on rule_ceshi.operation_log;
Query OK, 0 rows affected (0.19 sec)
Records: 0 Duplicates: 0 Warnings: 0 mysql> select count(*) from rule_ceshi.operation_log;
+----------+
| count(*) |
+----------+
| 21049180 |
+----------+
1 row in set (23.39 sec)

  上面的测试结果表明,count(*)走聚集索引和非聚集索引都是索引全扫描,但是走非聚集索引比走聚集索引获取记录数更快,这是为什么呢?我们通常不是说走主键索引是最快,难道这个原则在这里不适用还是优化器出现bug。当我产生这个疑问的时候,也曾这样怀疑,经过几次度娘和翻墙后,排除错误答案 ,终于可以很遗憾的告诉你主键索引确实是最快的,只是主键索引查询是有前提条件的,至于什么条件烦请查看我下一篇关于count(*)怎么走索引,走那种索引分析。

  2、上面的方式对单次查询,在足够配置的物理机上,显然我们还是可以接受的。然而很多次的类似sql出现,对数据库的性能也是一种不必要的损耗,因为这对业务发展并没有很深的意义。我们知道对于select count(*) from table_name这样的sql是没有办法通过索引优化的,那么只能通过改写sql进行优化了,这也是一个精通sql优化高手必备的技能。

  如果你也想精确查询表中的行数,又想查询的时间能尽可能短,这个时候我们就要想到max()和min()函数了,通常我们统计最大值和最小值都是很快返回结果的。

 mysql> select ifnull(max(id),0)-ifnull(min(id),0)+1 as rows from rule_ceshi.operation_log;
+----------+
| rows |
+----------+
| 21124162 |
+----------+
1 row in set (0.02 sec) mysql> explain select ifnull(max(id),0)-ifnull(min(id),0)+1 as rows from rule_ceshi.operation_log;
+----+-------------+-------+------+---------------+------+---------+------+------+------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+------------------------------+
| 1 | SIMPLE | NULL | NULL | NULL | NULL | NULL | NULL | NULL | Select tables optimized away |
+----+-------------+-------+------+---------------+------+---------+------+------+------------------------------+
1 row in set (0.01 sec)

  当然使用这种优化改写的前提是你的上产中表中有主键且是整数类型的,主键还需是连续的,也就是你的上产中没有进行过delete from table where xxx=xxx的删除行记录操作,否则这样统计还是不精准的。

  3、我们知道MySQL自带一个统计信息,平时我们的show命令之类的都来源数据库中的统计表。如果我们的Dev告诉我们,只需要模糊查询知晓表中数据行数呢?这个时候,你就可以通过MySQL自带的information_schema.tables表的统计信息,初步判断表的数据行大小。

mysql> select table_schema,table_name,table_type,table_rows from information_schema.tables where table_schema='rule_ceshi' and table_name='operation_log';
+--------------+---------------+------------+------------+
| table_schema | table_name | table_type | table_rows |
+--------------+---------------+------------+------------+
| rule_ceshi | operation_log | BASE TABLE | 20660338 |
+--------------+---------------+------------+------------+
1 row in set (0.01 sec) mysql> explain select table_schema,table_name,table_type,table_rows from information_schema.tables where table_schema='rule_ceshi' and table_name='operation_log';
+----+-------------+--------+------+---------------+-------------------------+---------+------+------+---------------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+--------+------+---------------+-------------------------+---------+------+------+---------------------------------------------------+
| 1 | SIMPLE | tables | ALL | NULL | TABLE_SCHEMA,TABLE_NAME | NULL | NULL | NULL | Using where; Open_full_table; Scanned 0 databases |
+----+-------------+--------+------+---------------+-------------------------+---------+------+------+---------------------------------------------------+
1 row in set (0.00 sec)

  上面这种方式对于dba日常维护,判断一个表的行数大小很有作用,必需知晓。

MySQL表行数查询最佳实践的更多相关文章

  1. MS SQL查询所有表行数,获取所有数据库名,表名,字段名

    1.获取所有数据库名 --SELECT Name FROM Master..SysDatabases ORDER BY Name -- 2.获取所有表名: --SELECT Name NAMEtemp ...

  2. MyBatis 用户表记录数查询

    搭建MyBatis开发环境,实现用户表记录数查询 1.在MyEclipse中创建工程,导入MyBatis的jar包

  3. SQL SERVER统计服务器所有的数据库(数据库文件)、表(表行数)、字段(各字段)等详细信息

    原文:SQL SERVER统计服务器所有的数据库(数据库文件).表(表行数).字段(各字段)等详细信息 USE STAT GO SET NOCOUNT ON IF EXISTS(SELECT 1 FR ...

  4. atitit.编辑表单的实现最佳实践dwr jq easyui

    atitit.编辑表单的实现最佳实践dwr jq easyui 1. 提交表单 1 2. 表单验证 1 3. 数据保存使用meger方式取代save&update方式 1 3.1. Filte ...

  5. 单表行数超过 500 万行或者单表容量超过 2GB,才推荐进行分库分表。

    https://github.com/alibaba/p3c/blob/master/阿里巴巴Java开发手册(详尽版).pdf 单表行数超过 500 万行或者单表容量超过 2GB,才推荐进行分库分表 ...

  6. MySQL 统计行数的 count

    MySQL count() 函数我们并不陌生,用来统计每张表的函数.但如果你的表越来越大,并且是 InnoDB 引擎的话,会发现计算的速度会越来越慢.在这篇文章里,会先介绍 count() 实现的原理 ...

  7. Mysql表分区的选择与实践小结

    在一些系统中有时某张表会出现百万或者千万的数据量,尽管其中使用了索引,查询速度也不一定会很快.这时候可能就需要通过分库,分表,分区来解决这些性能瓶颈. 一. 选择合适的解决方法 1. 分库分表. 分库 ...

  8. 一种快速统计SQL Server每个表行数的方法

    转载自:http://www.cnblogs.com/kenyang/archive/2013/04/09/3011447.html 我们都知道用聚合函数count()可以统计表的行数.如果需要统计数 ...

  9. SQL 从指定表筛选指定行信息 获取表行数

    1.获取指定表的行数 --获取表中数据行数 --select max([列名]) from 表名 2.筛选指定表的指定行数据(数据表分页获取) http://www.cnblogs.com/morni ...

随机推荐

  1. springBoot 使用拦截器 入坑

    近期使用SpringBoot 其中用到了拦截器 结果我的静态资源被全部拦截了,让我导致了好久才搞好: 看下图项目结构: 问题描述:上图划红框的资源都被拦截器给拦截了,搞得项目中不能访问:解决问题就是在 ...

  2. UE4杂记

    一些学习UE4时的笔记,转载请注明出处. ☆ UE4逻辑 Actor 是由 AActor 类派生而来的类实例:能被放入游戏世界场景的所有游戏性对象的基础类.对象是继承自 UObject 类的类实例:虚 ...

  3. 用idea部署maven-web项目

    项目部署时,需要加一步: 我们需要添加一个archetypeCatalog=internal.这个参数的意义是让这个maven项目的骨架不要到远程下载而是本地获取.如果你没加这个参数,那么项目创建可能 ...

  4. Unity3D编辑器扩展(五)——常用特性(Attribute)以及Selection类

    前面写了四篇关于编辑器的: Unity3D编辑器扩展(一)——定义自己的菜单按钮 Unity3D编辑器扩展(二)——定义自己的窗口 Unity3D编辑器扩展(三)——使用GUI绘制窗口 Unity3D ...

  5. Web Service CXF的工作流程

    我们一起走进系统的内部,跟随每一个调用,去透视系统的每一个层面. 一.我们定义整个目录都在CXFServlet的监控之下 <servlet> <servlet-name>CXF ...

  6. virtualenv虚拟环境

    1.你听过虚拟环境么? 虚拟:即不真实 环境:即周围的条件 那么到底什么事虚拟环境呢 2.虚拟环境 它是一个虚拟化,从电脑独立开辟出来的环境.通俗的来讲,虚拟环境就是借助虚拟机docker来把一部分内 ...

  7. fiddler两种方式设置断点

    第一种:打开Fiddler 点击Rules-> Automatic Breakpoint  ->Before Requests(这种方法会中断所有的会话) 如何消除命令呢?  点击Rule ...

  8. ubuntu设置ssh登录

    1.为ubuntu添加root用户(其实Ubuntu中的root帐号默认是被禁用了的,所以登陆的时候没有这个账号),打开初始账号,输入命令:sudo passwd root,设置root的密码 2.切 ...

  9. Git的分支管理

    0.引言 本文参考最后的几篇文章,将git的分支管理整理如下.学习git的分支管理将可以版本进行灵活有效的控制. 1.如何建立与合并分支 1.1分支的新建与合并指令 新建分支 newBranch,并进 ...

  10. 【webpack】-- 自动刷新与解析

    前端需要频繁的修改js和样式,且需要根据浏览器的页面效果不断的做调整:而且往往我们的开发目录和本地发布目录不是同一个,修改之后需要发布一下:另外一点就是并不是所有的效果都可以直接双击页面就能看到,我们 ...