InnoDB vs. TokuDB 写入性能测试

应用场景:

频繁插入/删除一个表中的数据,没有查询,需要评估InnoDB vs. TokuDB插入性能

TokuDB在开源后获得了大量关注,其采用的fractal tree相对于b+tree有着很好的随机插入性能,而查询性能也不低,How TokuDB Tree Indexes Work中介绍了其基本原理和理论性能公式,感兴趣可以阅读,本文将重点focus在性能数据上。

版本信息

mysql> select @@version;
+-------------------------+
| @@version               |
+-------------------------+
| 5.5.30-tokudb-7.0.1-log |
+-------------------------+
1 row in set (0.00 sec)

测试场景(一)

n个线程并发插入total_records条记录

a) 表定义:

CREATE TABLE `insert_test` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `a` int(11) DEFAULT NULL,
  `b` int(11) DEFAULT NULL,
  `c` varchar(128) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uniq_idx_bac` (`b`,`a`,`c`)
)

b) 数据生成

b = rand()
a = thread_id + n*k 
c = random_string(128)
PS: thread_id=[1..n], k=[0..total_records/n]

c) 配置my.cnf:

> TokuDB:默认配置

> InnoDB:

innodb_flush_method = O_DIRECT
innodb_file_per_table = 1
innodb_flush_log_at_trx_commit = 2
innodb_lock_wait_timeout = 100
innodb_additional_mem_pool_size = 20M
innodb_buffer_pool_size = 3G
innodb_log_buffer_size= 64M
innodb_log_file_size = 128M
innodb_log_files_in_group = 4
innodb_max_dirty_pages_pct = 75

d) 测试结果:

InnoDB vs. TokuDB insertion test 1
threads db type rows inserted time(s) data size
1 innodb 10000 0.99 14M
1 tokudb 10000 6.27 132K
1 innodb 100000 9.61 53M
1 tokudb 100000 63.51 8.2M
1 innodb 1000000 97.49 421M
1 tokudb 1000000 663.33 225M
1 innodb 10000000 1689.59 4.1G
1 tokudb 10000000 6941.54 2.7G
4 innodb 10000 0.53 - –
4 tokudb 10000 3.04 - –
4 innodb 100000 4.84 - –
4 tokudb 100000 31.07 - –
4 innodb 1000000 48.79 - –
4 tokudb 1000000 318.02 - –
4 innodb 10000000 568.05 - –
4 tokudb 10000000 3267.52 - –
32 innodb 10000 0.58 - –
32 tokudb 10000 1.06 - –
32 innodb 100000 5.72 - –
32 tokudb 100000 10.65 - –
32 innodb 1000000 58.47 - –
32 tokudb 1000000 106.41 - –
32 innodb 10000000 633.58 - –
32 tokudb 10000000 1120.16 - –

e) 基本结论:

1. 在该场景下,InnoDB是按照主键自增的顺序插入记录的,同时维护一个二级索引(引入了随机IO),TokuDB的插入性能落后于InnoDB(对于B+tree而言,3层)
2. TokuDB有着较好的数据压缩率,官方宣称的2~4倍于InnoDB的结论基本成立

f) 分析

B+tree能够提供较好的查询性能是因为其较高的扇出,通常来说,InnoDB中千万级别记录数的表只需要一颗3层的B+tree就可以保存(一个页面16KB,非叶子节点一个Index entry大概数十Byte,一个page可以存放500~1000左右的指向下层页面的指针,叶子节点保存了完整数据,能够存放的记录数较少,按照一条记录大约占用200 bytes来算,一个page可以存放80条记录,因此一颗三层的B+tree可以存放的记录是:500*500*80=2kw,如果主键能够更短的话,1000*1000*80=8kw,可以参考Jeremy Cole博客),通常第一和第二层非叶子节点页面基本在内存中,因此一次查询最多一次IO,而由于Buffer pool的存在,查询性能进一步得到提升

本测试插入的最大记录数10000000,因此B+tree的层数(3)其实还是较少的,插入时间基本上随插入记录随呈线性增长,TokuDB宣称的比InnoDB更好的插入性能应该是在更大的记录数的前提上,测试二将验证这个猜测

测试场景(二)

与测试(一)不同,本次测试使用iibench工具,python版本出自大牛Mark Callaghan,测试中单线程插入31kw条记录,统计每插入一定数目记录消耗的时间插入时间来计算IPS(Insert Per Second),对比InnoDB与TokuDB的性能

a) 建表信息

CREATE TABLE `purchases_index` (
  `transactionid` int(11) NOT NULL AUTO_INCREMENT,
  `dateandtime` datetime DEFAULT NULL,
  `cashregisterid` int(11) NOT NULL,
  `customerid` int(11) NOT NULL,
  `productid` int(11) NOT NULL,
  `price` float NOT NULL,
  `data` varchar(4000) DEFAULT NULL,
  PRIMARY KEY (`transactionid`),
  KEY `marketsegment` (`price`,`customerid`),
  KEY `registersegment` (`cashregisterid`,`price`,`customerid`),
  KEY `pdc` (`price`,`dateandtime`,`customerid`)
);

b) 测试脚本

./iibench.py --db_socket=mysql.sock --db_user=root --insert_only --setup --max_rows=310000000 --rows_per_commit=10 --tokudb_commit_sync=0 --engine=innodb
./iibench.py --db_socket=mysql.sock --db_user=root --insert_only --setup --max_rows=310000000 --rows_per_commit=10 --tokudb_commit_sync=0 --engine=tokudb

每个insert语句插入10条记录,每插入100w行记录report插入时间(用于计算IPS),插入时按照主键自增的顺序插入,同时维护3个二级索引(随机IO)

c) 结果对比图:

iibench_innodb_vs_tokudb

d) 结论

1. 在插入数据量规模在大约3.1kw之前,InnoDB的插入性能要好于TokuDB,而在继续插入时,InnoDB插入性能下降厉害
2. TokuDB插入性能一直很稳定,在表数据规模很大时也能保持插入性能,因而对于超大表(>=10kw级别),TokuDB较InnoDB有较大优势
3. 线上应用采取分库分表策略,单表容量一般不超过500w条记录,因此此时InnoDB较TokuDB有优势

e) 分析

可能原因:InnoDB表在插入在3.1kw之后,索引B+tree由3层变成4层,每次随机插入相对于3层结构会增加一次IO

f) my.cnf 参数

与测试(一)中相同

g) 调整 innodb_buffer_pool_size = 8GB,测试增大buffer pool效果

iibench_innodb_vs_tokudb

测试场景(三)

采用load data infile方式加载数据,数据量5亿条,按照主键ID自增load数据,load时不维护任何索引,由于数据量(>200G)超过内存大小,将数据文件切分成100w条一个 然后一个文件一个文件load
统计每个文件load完成的时间 根据load的总条数/load时间 计算每导入100w条记录的速度

a) 表模式

table_struct='(
  `transactionid` int(11) NOT NULL AUTO_INCREMENT,
  `dateandtime` datetime DEFAULT NULL,
  `cashregisterid` int(11) NOT NULL,
  `customerid` int(11) NOT NULL,
  `productid` int(11) NOT NULL,
  `price` float NOT NULL,
  `data` varchar(400) DEFAULT NULL,
  PRIMARY KEY (`transactionid`)
)'

b) 参数配置

innodb_buffer_pool_size = 8GB
其它配置与测试(一)中相同

c) 性能结果图

load_innodb_vs_tokudb

d) 分析

1. InnoDB中btree在顺序写入方面,由于带来的随机IO较少的缘故,写入性能能够一直保持较高的水平,测试结果显示比TokuDB好
2. 顺序写入InnoDB和TokuDB写入性能都很稳定

《InnoDB vs. TokuDB 写入性能测试》上有2条评论

  1. Interesting evaluation result. Nice work!

    Seen from the result, with 3-leveled btree, innodb works better than tokudb while once the btree is more full to split, the perf drops dramatically. As for the table record number, it’s mostly depended on the record size, as well as the BP size.

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注