Mysql的JSON与SequoiaDB的比较

 Mysql从5.7开始,支持原生的json, 也有不少的工程师建议采用mysql来取代文本数据库。下面将介绍json在mysql与国内的nosql文档数据库sequoiaDB的操作方式,存储,以及高可用性架构方面的不同,通过介绍之后,至于在什么情况下该使用seqoiaDB以及什么情况下使用Mysql,基本可以选择正确的方案。


1        操作方式比较

1.1     Mysql数据库操作

创建一个表,只含有json字段。

mysql> CREATE TABLE t1 (jdoc JSON);

Query OK, 0 rows affected (0.20 sec)

 

1.1.1         Insert操作

mysql> insert into t1  values(JSON_OBJECT('key1', 1, 'key2','abc'));

Query OK, 1 row affected (0.01 sec)

 

mysql> select * from t1;

+----------------------------+

| jdoc                       |

+----------------------------+

| {"key1": 1, "key2":"abc"} |

+----------------------------+

1 row in set (0.00 sec)

 

mysql> set @j=repeat('x',60000);

Query OK, 0 rows affected (0.00 sec)

 

mysql> insert into  t1 values(JSON_OBJECT('key', @j));

Query OK, 1 row affected (4.72 sec)

 

mysql> insert into  t1 values(JSON_OBJECT('key', @j));

Query OK, 1 row affected (1 min 6.79 sec)

 

 

(gdb) c

Continuing.

 

Breakpoint 3, dtuple_convert_big_rec(index=0x7f54e0144d10, upd=0x0, entry=0x7f54e01584d0,n_ext=0x7f55a2bf4708)

   at /data/mysql/mysql-5.7.10/storage/innobase/data/data0data.cc:591

591             if (!dict_index_is_clust(index)) {

 

 

命中断点dtuple_convert_big_rec, 将json 字段以大字段存储。

 

 

当执行insert into t1  values('["key1", 1,"key2", "abc"]'); 这样的操作时,因为字段jdoc的类型是json类型,所以对该列的值会用Json_dom::parse函数进行词法分析,如果是json格式,则通过。

 

(gdb) c

Continuing.

 

Breakpoint 2, Json_dom::parse(text=0x7f54e000f948 "[\"key1\", 1, \"key2\",\"abc\"]", length=26, syntaxerr=0x7f55a2bf5f18,offset=0x7f55a2bf5f10,

    preserve_neg_zero_int=false)at /data/mysql/mysql-5.7.10/sql/json_dom.cc:865


1.1.2         json的函数

 

在mysql中,json区分大小,大写的null无法转化为json类型。

mysql> SELECT CAST('NULL' AS JSON);

ERROR 3141 (22032): Invalid JSON text inargument 1 to function cast_as_json: "Invalid value." at position 0in 'NULL'.

mysql> SELECT CAST('null' AS JSON);

+----------------------+

| CAST('null' AS JSON) |

+----------------------+

| null                 |

 

 

 

 

mysql> SELECT JSON_MERGE('[1, 2]','["a", "b"]', '[true, false]');

+-----------------------------------------------------+

| JSON_MERGE('[1, 2]', '["a","b"]', '[true, false]') |

+-----------------------------------------------------+

| [1, 2, "a", "b",true, false]                       |

+-----------------------------------------------------+

1 row in set (7.72 sec)

 

Breakpoint 2, Json_dom::parse(text=0x7f54e000f938 "[1, 2]", length=6, syntaxerr=0x7f55a2bf5a90,offset=0x7f55a2bf5a88, preserve_neg_zero_int=false)

   at /data/mysql/mysql-5.7.10/sql/json_dom.cc:865

865      Rapid_json_handler handler(preserve_neg_zero_int);

(gdb) c

Continuing.

 

Breakpoint 2, Json_dom::parse(text=0x7f54e000faf0 "[\"a\", \"b\"]", length=10,syntaxerr=0x7f55a2bf5a90, offset=0x7f55a2bf5a88, preserve_neg_zero_int=false)

   at /data/mysql/mysql-5.7.10/sql/json_dom.cc:865

865      Rapid_json_handler handler(preserve_neg_zero_int);

(gdb) c

Continuing.

 

Breakpoint 2, Json_dom::parse(text=0x7f54e000fc88 "[true, false]", length=13,syntaxerr=0x7f55a2bf5a90, offset=0x7f55a2bf5a88, preserve_neg_zero_int=false)

   at /data/mysql/mysql-5.7.10/sql/json_dom.cc:865

865      Rapid_json_handler handler(preserve_neg_zero_int);



其他示例操作省略介绍。。。。。。 , 请参考官方文档,json 的基本操作都有。

 

总结:经过简单跟踪对含有json 字段的表的sql操作获悉,对在mysql中支持json的理解,

   可以简单地将json的类型类比其他的数据类型,如int,  datetime等,它是mysql支持的一种数据类型,仅仅而已。就算仅仅创建一个只有一个json 类型的字段的表(如图上的示例T1,就只有一个jdoc的json类型的例)。 对于json列的更新(包括插入)操作,会调用Json_dom::parse  进行json类型的值合法性检查,同时,mysql中包含了许多json类型的操作函数(如上示例的操作),对于只包含一个json列的表进行插入操作,其需要执行的函数逻辑跟一个普通表的insert 完全一致, 最终将json字段以大字段类型lob类型存储到innodb 的存储引擎中。

 

所以从本质上来讲,mysql 5.7 支持json , 实际上是扩展了一个数据类型,通过扩展一些操作函数来支持json的数据类型,该数据类型最终以大字段类型lob的方式存储在innodb 存储引擎中。

 

从上面的分析得知,mysql支持json ,但依然是在原来sql处理方式,来支持json的数据类型。当表中含有json字段时,我们可以当其时一个blob 字段,但这个列中的每一个数据项,都是一个json的文档对象,支持很多json类型的操作。


正是因为json仅仅是mysql的数据库表中的一个lob的类型字段 ,所以,其性能也跟普通的包含blob字段类型的表无异。当行的长度较短时,支持非常高的读写并发操作,但同样,如果json字段的长度很长,操作时会带来大量的IO操作,QPS自然下降。


2      性能比较

1.1     插入性能

   以下是进行的长json类型的比较测试,json的文档大小为32K ,测试结果如下:

1.1.1         SequoiaDB

测试结果:(当集合表中的数据量越大,insert性能越慢),从空表开始,每个测试线程执行一个20000 insert的文件

 

file_no:1-0 runing_num: 1   total_time: 66   qps: 303 run_script: test_sdb.sh comment:test  sdb  on phyiscal machine   32k sharding by  6 replication group

file_no:21-1 runing_num: 20   total_time: 276   qps: 1449 run_script: test_sdb.sh comment:test  sdb  on phyiscal machine   32k sharding by  6 replication group

file_no:21-20 runing_num: 1   total_time: 70   qps: 285 run_script: test_sdb.sh comment:test  sdb  on phyiscal machine   32k sharding by  6 replication group

file_no:21-1 runing_num: 20   total_time: 433   qps: 923 run_script: test_sdb.sh comment:test  sdb  on phyiscal machine   32k sharding by  6 replication group

file_no:21-1 runing_num: 20   total_time: 837   qps: 477 run_script: test_sdb.sh comment:test  sdb  on phyiscal machine   32k sharding by  6 replication group

 (简单说明一下测试结果 : runing_num为并发执行 sql的会话数 ,total_time为总的执行时间, qps就是每秒(插入)的执行数 ,后面是 备注 ) 

如果是12个复制组的插入性能如下:

file_no:1-0 runing_num: 1   total_time: 64   qps: 312 run_script: test_sdb.sh comment:test  sdb  on phyiscal machine   32k sharding by  12 replication group

file_no:20-1 runing_num: 19   total_time: 144   qps: 2638 run_script: test_sdb.sh comment:test  sdb  on phyiscal machine   32k sharding by  12 replication group

file_no:20-1 runing_num: 19   total_time: 160   qps: 2375 run_script: test_sdb.sh comment:test  sdb  on phyiscal machine   32k sharding by  12 replication group

file_no:23-1 runing_num: 22   total_time: 183   qps: 2404 run_script: test_sdb.sh comment:test  sdb  on phyiscal machine   32k sharding by  12 replication group

file_no:23-1 runing_num: 22   total_time: 210   qps: 2095 run_script: test_sdb.sh comment:test  sdb  on phyiscal machine   32k sharding by  12 replication group

file_no:23-1 runing_num: 22   total_time: 210   qps: 2095 run_script: test_sdb.sh comment:test  sdb  on phyiscal machine   32k sharding by  12 replication group

file_no:23-1 runing_num: 22   total_time: 205   qps: 2146 run_script: test_sdb.sh comment:test  sdb  on phyiscal machine   32k sharding by  12 replication group

file_no:23-13 runing_num: 10   total_time: 123  qps: 1626 run_script: test_sdb.sh comment:test  sdb  on phyiscal machine   32k sharding by  12 replication group

 

 

如果是单复制组,则结果如下

 

(测试Sdb单复制组的情况,每个线程执行2万insert .)

file_no:1-0 runing_num: 1   total_time: 64   qps: 312 run_script: test_sdb.sh    comment:test  sdb  on phyiscal machine   32k no sharding  1  replication group

file_no:11-1 runing_num: 10   total_time: 249   qps: 803 run_script: test_sdb.sh comment:test  sdb  on phyiscal machine   32k no sharding  1  replication group

file_no:20-1 runing_num: 19   total_time: 500   qps: 760 run_script: test_sdb.sh comment:test  sdb  on phyiscal machine   32k no sharding  1  replication group

 

可以看到,复制组越多,也就是分片越多,支持的并发插入的qps就越多。

 

1.1.2         Mysql的插入性能

mysql单库的测试结果,json列的大小为32k。  每个sql文件20000行,总共插入40万记录,表文件大小13329498112

 

file_no:5-0 runing_num: 5   total_time: 82   qps: 1219 run_script: xcytest.sh comment:test  mysql  big json column

file_no:20-10 runing_num: 10   total_time: 197   qps: 1015 run_script: xcytest.sh comment:test  mysql  big json column

file_no:25-20 runing_num: 5   total_time: 99   qps: 1010 run_script: xcytest.sh comment:test  mysql  big json column

 

1.1.3         插入性能对比总结

    本次测试的是32K的行的插入性能,从上面的对比可以看出,Mysql的单机性能不如6个复制组以上的分片。且SequoiaDB 的分片数越多,插入性能越大。

 

但需要指出的是,如果是小行插入,如行的大小100byte左右,则mysql的性能远胜于SequoiaDB ,在CPU只有4核的机器上,跑出3万多的insert的qps。 而在sequioadb 上,只能跑出不到15000的qps.




上一篇:UOJ#195. 【ZJOI2016】大♂森林 LCT


下一篇:linux创建文件系统