主键乱序插入对Innodb性能的影响
主键乱序插入对Innodb性能的影响
在平时的mysql文档学习中我们经常会看到这么一句话:
MySQL tries to leave space so that future inserts do not incur un-necessary page splits (and thus higher IO cost). In an "ideal" world, MySQL tries to keep the index pages at 15/16-th full, but depending on insert order, this fill factor can be as low as 1/2
大致含义就是当我们按照索引顺序插入时,page的填充率能达到15/16 , 而乱序插入时只能到略大于 1/2 的填充率。
那么这个说法是否正确呢?是否有相应的理论依据呢?
本文将通过一些测试来验证这个观点的真伪。
测试数据准备
简介: 顺序数据通过sysbench --oltp-table-size = 8000000 生成,然后通过order by rand() 生成乱序数据。
mysql> desc sbtest; + -------+------------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | + -------+------------------+------+-----+---------+----------------+ | id | int (10) unsigned | NO | PRI | NULL | auto_increment | | k | int (10) unsigned | NO | MUL | 0 | | | c | char (120) | NO | | | | | pad | char (60) | NO | | | | + -------+------------------+------+-----+---------+----------------+ |
#顺序文件<BR>mysql> select * from sbtest into outfile '/xfs/mysql3311/order.txt' ;<BR>#乱序文件 mysql> select b.* from rand_num a left join sbtest b on a.id = b.id into outfile '/xfs/mysql3311/random-order.txt' ; |
文件load 性能测试
从结果可以很明显的看出 53sec vs 719sec,加载速度慢了12倍之多。
通过B-tree的原理我们也可以知道,乱序插入时Innodb需要不停的申请新的page,并且进行tree的重新分布,导致插入速度变慢。
CREATE TABLE `sbtest_order` ( `id` int (10) unsigned NOT NULL AUTO_INCREMENT, `k` int (10) unsigned NOT NULL DEFAULT '0' , `c` char (120) NOT NULL DEFAULT '' , `pad` char (60) NOT NULL DEFAULT '' , PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; |
mysql> load data infile '/xfs/mysql3311/order.txt' into table sbtest_order;
Query OK, 8000000 rows affected (53.23 sec)
Records: 8000000
Deleted: 0 Skipped: 0 Warnings: 0
CREATE TABLE `sbtest_rand` ( `id` int (10) unsigned NOT NULL AUTO_INCREMENT, `k` int (10) unsigned NOT NULL DEFAULT '0' , `c` char (120) NOT NULL DEFAULT '' , `pad` char (60) NOT NULL DEFAULT '' , PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; |
mysql> load data infile '/xfs/mysql3311/random-order.txt' into table
sbtest_random;
Query OK, 8000000 rows affected (11 min 59.09 sec)
Records: 8000000
Deleted: 0 Skipped: 0 Warnings: 0
页面填充率
通过xtrabackup的附带功能查看数据文件,可以知道page填充率。
从下文标红的数据可以看到:
- 顺序的page填充率= 92% = 15/16
- 乱序的page填充率= 65% = 10/16
基本和理论值一致
shell> xtrabackup --defaults-file=/usr/local/mysql3311/my.cnf --stats
--tables="sbtest[.]sbtest_order*"
--datadir=/xfs/mysql3311<INDEX STATISTICS>
table: sbtest/sbtest_order, index: PRIMARY,
space id: 11, root page: 3, zip size: 0
estimated statistics in
dictionary:
key vals: 8000079, leaf pages: 109590, size pages: 109696
real
statistics:
level 2 pages: pages=1, data=1196 bytes, data/pages=7%
level 1
pages: pages=92,
data=1424670 bytes, data/pages=94%
leaf pages: recs=8000000, pages=109590,
data=1664000000 bytes, data/pages=92%
shell> xtrabackup --defaults-file=/usr/local/mysql3311/my.cnf --stats
--tables="sbtest[.]sbtest_random*"
--datadir=/xfs/mysql3311
<INDEX STATISTICS>
table:
sbtest/sbtest_random, index: PRIMARY, space id: 12, root page: 3, zip size:
0
estimated statistics in dictionary:
key vals: 8916256, leaf pages:
155403, size pages: 177920
real statistics:
level 2 pages: pages=1,
data=2899 bytes, data/pages=17%
level 1 pages: pages=223, data=2020239 bytes,
data/pages=55%
leaf pages: recs=8000000, pages=155403, data=1664000000 bytes,
data/pages=65%
查询性能测试:
使用8并发的sysbench进行OLTP测试,查看两种方式的性能差异。
- TPQ:3078 vs 2803 约10%性能损耗
- Res:2.75ms vs 3.85ms 约40%性能损耗
- Data Size:1.8G vs 2.8G 1.5倍的空间损耗
sysbench --num-threads=8 --max-time=60 --max-requests=9999999 --test=oltp
--oltp-table-size=8000000 --mysql-socket=/xfs/mysql3311/mysql.sock
--mysql-user=root --mysql-password=password --mysql-table-engine=innodb --oltp-table-name=sbtest_order
runtransactions: 184697 (3078.18 per
sec.)
deadlocks: 0 (0.00 per sec.)
read/write requests:
3509243 (58485.34 per sec.)
other operations: 369394 (6156.35 per sec.)approx. 95 percentile: 2.75ms
sysbench --num-threads=8 --max-time=60 --max-requests=9999999 --test=oltp
--oltp-table-size=8000000 --mysql-socket=/xfs/mysql3311/mysql.sock
--mysql-user=root --mysql-password=password --mysql-table-engine=innodb --oltp-table-name=sbtest_random
runtransactions: 168213 (2803.44 per
sec.)
deadlocks: 0 (0.00 per sec.)
read/write requests:
3196047 (53265.34 per sec.)
other operations: 336426 (5606.88 per sec.)approx. 95 percentile:
3.85ms
总结
通过测试可以看出,按照主键的顺序插入可以带来10%的TPS提升,并能减少50%的空间浪费。
在平时的开发过程中,如果没有特别的业务需要,应该尽可能的使用自增列作为主键。
主键乱序插入对Innodb性能的影响的更多相关文章
- InnoDB的主键选择与插入优化
索引的存放方式MyISAM和InnoDB存储引擎在MySQL中,不同存储引擎对索引的实现方式是不同的,总结下MyISAM和InnoDB两个存储引擎的索引实现方式.MyISAM引擎使用B+Tree作为索 ...
- SQLServer 自增主键创建, 指定自增主键列值插入数据,插入主键
http://blog.csdn.net/zh2qiang/article/details/5323981 SQLServer 中含自增主键的表,通常不能直接指定ID值插入,可以采用以下方法插入. 1 ...
- Phoenix表和索引分区数对插入和查询性能的影响
1. 概述 1.1 HBase概述 HBase由master节点和region server节点组成.在100-105集群上,100和101是master节点,102-105是region serve ...
- MyBatis魔法堂:Insert操作详解(返回主键、批量插入)
一.前言 数据库操作怎能少了INSERT操作呢?下面记录MyBatis关于INSERT操作的笔记,以便日后查阅. 二. insert元素 属性详解 其属性如下: parameterType ...
- MyBatis :Insert (返回主键、批量插入)
一.前言 数据库操作怎能少了INSERT操作呢?下面记录MyBatis关于INSERT操作的笔记,以便日后查阅. 二.insert元素 属性详解 其属性如下: parameterType , ...
- MySQL数据表中有自增长主键时如何插入数据
原文链接:https://blog.csdn.net/RuobaiMEN/article/details/79794199 MySQL数据库表中有自增主键ID,当用SQL插入语句中插入语句带有ID列值 ...
- Mysql EF 触发器生成主键id 存储区更新、插入或删除语句影响到了意外的行数(0)。实体在加载后可能被修改或删除。刷新 ObjectStateManager 项 ;System.Data.Entity.Infrastructure.DbUpdateConcurrencyException
http://stackoverflow.com/questions/24725261/how-to-use-a-custom-identity-column-in-sql-with-entity-f ...
- 关于前台主键输入错误对后台hibernate方法的影响
由于前台输入时开始不小心打错了主键为value=“${conf_id}”/ 导致后台得到的主键不是数字“1”而是“1/”所以到后台就算是进的updata方法结果运行的却是添加方法 原因可能是传入的对象 ...
- sql server中主键列的插入问题
仅当使用了列列表并且 IDENTITY_INSERT 为 ON 时,才能为表'dbo.t_test'中的标识列指定显式值. SET IDENTITY_INSERT dbo.t_test ON ,'c' ...
随机推荐
- [UIKit学习]06.懒加载,模型,自定义代码段,重写构造方法
懒加载 在get中加载,且只加载一次 - (NSArray *)shops { if (_shops == nil) { NSString *file = [[NSBundle mainBundle] ...
- ArrayList底层实现原理
ArrayList概述: ArrayList是List接口的可变数组的实现.实现了所有可选列表操作,并允许包括null在内的所有元素.除了实现列表接口外,此类还提供一些方法来操作内部用来存储列表的数组 ...
- C#操作SqlServer MySql Oracle通用帮助类Db_Helper_DG(默认支持数据库读写分离、查询结果实体映射ORM)
[前言] 作为一款成熟的面向对象高级编程语言,C#在ADO.Net的支持上已然是做的很成熟,我们可以方便地调用ADO.Net操作各类关系型数据库,在使用了多年的Sql_Helper_DG后,由于项目需 ...
- JAVA多线程---volatile关键字
加锁机制既可以确保可见性又可以保证原子性,而volatile变量只能确保可见性. 当把变量声明为volatile时候 编译器与运行时都会注意到这个变量是共享的,不会将该变量上的操作与其他内存操作一起重 ...
- ASP.NET Core中如何调整HTTP请求大小的几种方式
一.前言 一般的情况下,我们都无需调用HTTP请求的大小,只有在上传一些大文件,或者使用HTTP协议写入较大的值时(如调用WebService)才可能会调用HTTP最大请求值. 在ASP.NET Co ...
- Cookie实现登录记住密码
Cookie实现记住登录密码,用户可以自由选择是否记住密码,或者用户之前选择记住了,但是某一次又不想记住了,需要将之前对应的Cookie删除掉 Cookie相当于map 也是键值对的形式,但是并不相同 ...
- java集合系列——Map介绍(七)
一.Map概述 0.前言 首先介绍Map集合,因为Set的实现类都是基于Map来实现的(如,HashSet是通过HashMap实现的,TreeSet是通过TreeMap实现的). 1:介绍 将键映射到 ...
- Running Spark on YARN
Running Spark on YARN 对 YARN (Hadoop NextGen) 的支持是从Spark-0.6.0开始的,后续的版本也一直持续在改进. Launching Spark on ...
- input中range相关操作
利用mousover触发函数对range的操作练习 <!DOCTYPE html> <html> <head> <meta charset="utf ...
- Ionic3学习笔记(一)安装、项目结构与常用命令
本文为原创文章,转载请标明出处 目录 安装 项目结构 常用命令 1. 安装 安装Cordova.Ionic npm install -g cordova ionic 创建一个新项目,有blank.ta ...