mysql count(*) count(1) count(id) 讲解 千万数据测试

為{幸葍}努か 提交于 2020-08-08 16:53:06

数据100万增加到 1000万测试数据

环境 win10 8g内存 mysql5.7.27

mysql my.ini 配置 注意(innodb_flush_log_at_trx_commit=0)配置

[Client]
#设置3306端口
port = 3306
[mysqld]
#设置3306端口
port = 3306
# 设置mysql的安装目录
basedir=E:devmysql-5.7.27-winx64
# 设置mysql数据库的数据的存放目录
datadir=E:devmysql-5.7.27-winx64data
# 允许最大连接数
max_connections=200
# 服务端使用的字符集默认为8比特编码的latin1字符集
character-set-server=utf8
# 创建新表时将使用的默认存储引擎
default-storage-engine=INNODB
sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES

# 插入数据时设置为0提高插入数据,插入数据完成修改为1
innodb_flush_log_at_trx_commit=0  

[mysql]
# 设置mysql客户端默认字符集
default-character-set=utf8

1、创建表

CREATE TABLE `test_count` (
  `id` bigint(11) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(60) DEFAULT NULL,
  `age` int(3) DEFAULT NULL,
  `create_time` datetime DEFAULT NULL,
  `test1` varchar(100) DEFAULT NULL,
  `test2` varchar(100) DEFAULT NULL,
  `test3` varchar(100) DEFAULT NULL,
  `test4` varchar(100) DEFAULT NULL,
  `test5` varchar(100) DEFAULT NULL,
  `test6` varchar(100) DEFAULT NULL,
  `test10` varchar(100) DEFAULT NULL,
  `test11` varchar(100) DEFAULT NULL,
  `test12` varchar(100) DEFAULT NULL,
  `test13` varchar(200) DEFAULT NULL,
  `test14` varchar(200) DEFAULT NULL,
  `test15` varchar(200) DEFAULT NULL,
  `test16` varchar(200) DEFAULT NULL,
  `test17` varchar(200) DEFAULT NULL,
  `test18` varchar(200) DEFAULT NULL,
  `test19` varchar(200) DEFAULT NULL,
  `test20` varchar(200) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8;

2、创建存储过程

CREATE  PROCEDURE `test_count_dure`(IN n int)
BEGIN  
  DECLARE i INT DEFAULT 1;
    WHILE (i <= n ) DO
      INSERT into test_count  (name,age,create_time,test1,test2,test3,test4,test5,test6,test10,test11,test12,test13,test14,test15,test16,test17,test18,test19,test20 ) VALUEs 
															(i,100 ,now(),'213dfdsjfdasfdsdafdffsd',
'213dfdsjfdasfdsdafdffsd','213dfdsjfdasfdsdafdffsd','213dfdsjfdasfdsdafdffsd'
,'213dfdsjfdasfdsdafdffsd','213dfdsjfdasfdsdafdffsd','afdasfjdlajlfkalfdakfjdlajfkalfdasfd','afdasfjdlajlfkalfdakfjdlajfkalfdasfd','afdasfjdlajlfkalfdakfjdlajfkalfdasfd','afdasfjdlajlfkalfdakfjdlajfkalfdasfd','afdasfjdlajlfkalfdakfjdlajfkalfdasfd','afdasfjdlajlfkalfdakfjdlajfkalfdasfd','afdasfjdlajlfkalfdakfjdlajfkalfdasfd','afdasfjdlajlfkalfdakfjdlajfkalfdasfd','afdasfjdlajlfkalfdakfjdlajfkalfdasfd','afdasfjdlajlfkalfdakfjdlajfkalfdasfd','afdasfjdlajlfkalfdakfjdlajfkalfdasfd' );
			set i=i+1;
    END WHILE;
END

3、创建100万数据

CALL test_count_dure(1000000);

4、查看表占用磁盘大小

SELECT CONCAT(TRUNCATE(SUM(data_length)/1024/1024,2),'MB') AS data_size,
CONCAT(TRUNCATE(SUM(max_data_length)/1024/1024,2),'MB') AS max_data_size,
CONCAT(TRUNCATE(SUM(data_free)/1024/1024,2),'MB') AS data_free,
CONCAT(TRUNCATE(SUM(index_length)/1024/1024,2),'MB') AS index_size
FROM information_schema.tables WHERE TABLE_NAME = 'test_count';

5、执行count

count(1) count(*) count(1) 基本都在 8秒

强制使用 主键当做索引 时间还是 8秒

6、增加test_count 二级索引

给name 加一个普通索引
CREATE TABLE `test_count` (
  `id` bigint(11) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(60) DEFAULT NULL,
  `age` int(3) DEFAULT NULL,
  `create_time` datetime DEFAULT NULL,
  `test1` varchar(100) DEFAULT NULL,
  `test2` varchar(100) DEFAULT NULL,
  `test3` varchar(100) DEFAULT NULL,
  `test4` varchar(100) DEFAULT NULL,
  `test5` varchar(100) DEFAULT NULL,
  `test6` varchar(100) DEFAULT NULL,
  `test10` varchar(100) DEFAULT NULL,
  `test11` varchar(100) DEFAULT NULL,
  `test12` varchar(100) DEFAULT NULL,
  `test13` varchar(200) DEFAULT NULL,
  `test14` varchar(200) DEFAULT NULL,
  `test15` varchar(200) DEFAULT NULL,
  `test16` varchar(200) DEFAULT NULL,
  `test17` varchar(200) DEFAULT NULL,
  `test18` varchar(200) DEFAULT NULL,
  `test19` varchar(200) DEFAULT NULL,
  `test20` varchar(200) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `name` (`name`) USING BTREE
) ENGINE=InnoDB  DEFAULT CHARSET=utf8;

7、再次执行 count(1) count(*) count(1)

通过多次执行
count(*) count(1) 执行时间 在 0.2~0.3秒
count(id) 执行时间 在 0.3~0.4秒
通过explain 执行计划查看 使用的是二级索引 name索引 从而提高了查询速度

8、通过网上查询得知为什么加入一个二级索引速度就快了的原因

1)普通查询

普通查询使用主键索引是最快的,整体IO消耗也最少,使用二级索引时,由于先要根据二级索引定位到主健索引,再根据主健索引查询数据文件,IO消耗比主键索引大

2)统计查询

统计类需求,如COUNT之类的,反而使用二级索引比主键索引性能更高,因为MYSQL使用B+树,主健索引与数据共同存放在B+树叶子结点,如果使用主健索引进行统计时,每次都要扫描数据文件,当数据字段及行数较多时(数据文件较大),扫描时IO消耗较高。而二级索引只存放索引数据,索引文件比较小,不需要搜索数据文件,整体IO消耗低

count(*)=count(1)>=count(primarykey)>=count(非空字段)>=count(可为空字段)

数据增加1000万测试用例

首先看下数据磁盘占用空间 单表6G

test_count表增加字段

# 增加x1字段
ALTER TABLE `test_count`
ADD COLUMN `x1`  char(1) NOT NULL DEFAULT 'a';
# 增加x1字段索引
ALTER TABLE `test_count`
ADD INDEX `x1` (`x1`) USING BTREE ;

查看count(* ) 3.7秒 3~4秒之间

查看count(1) 3.8秒 3~4秒之间

查看count (id) 4.058 秒 3.9~4 秒以上

查看表索引情况

mysql> show index from test_count;
+------------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table      | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+------------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| test_count |          0 | PRIMARY  |            1 | id          | A         |     9441071 | NULL     | NULL   |      | BTREE      |         |               |
| test_count |          1 | name     |            1 | name        | A         |     7791336 | NULL     | NULL   | YES  | BTREE      |         |               |
| test_count |          1 | x1       |            1 | x1          | A         |           1 | NULL     | NULL   |      | BTREE      |         |               |
+------------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
3 rows in set

在上面测试的时候发现默认走的是name 索引,这次为什么走了x1 索引

mysql> EXPLAIN
SELECT count(*) from test_count;
+----+-------------+------------+------------+-------+---------------+-----+---------+------+---------+----------+-------------+
| id | select_type | table      | partitions | type  | possible_keys | key | key_len | ref  | rows    | filtered | Extra       |
+----+-------------+------------+------------+-------+---------------+-----+---------+------+---------+----------+-------------+
|  1 | SIMPLE      | test_count | NULL       | index | NULL          | x1  | 3       | NULL | 9606635 |      100 | Using index |
+----+-------------+------------+------------+-------+---------------+-----+---------+------+---------+----------+-------------+
1 row in set

查看强制使用 name当索引执行时间 15秒

x1 char(1) NO MUL a (char(1)长度)

name varchar(60) YES MUL (varchar(60)长度)

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!