欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-04-09 19:40:36
...

数据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';

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

5、执行count

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

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

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

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

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)

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

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

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

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

1)普通查询

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

2)统计查询

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

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

数据增加1000万测试用例

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

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

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秒之间

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

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

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

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

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

查看表索引情况

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)长度)

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

相关标签: mysql