mysql5.7 json vs mongodb json

都知道mysql5.7提供了json类型,mongodb也是有json,作为dba,经常有rd咨询如何选择的问题。
下面对比了5.7的json和mongodb的json,可以看出来应该怎么选择了。

一:测试数据准备
mysql> select count() from m_test;
±---------+
| count(
) |
±---------+
| 20999199 |
±---------+
mongodb
db.test2.count();
21000001

都是2千万的记录
mysql的buffer设置了12g,数据文件也是12g,基本上都是内存操作了

 db.test2.find().limit(1);
{ "_id" : ObjectId("5e205cf703eb69e9acd2f0c7"), "user_basic_info" : { "name" : "张三", "age" : "29", "address" : { "city" : "上海", "province" : "上海" } }, "work_exprs" : [ { "company" : "公司999999", "date_range" : "2001-2003" }, { "company" : "公司999999999999", "date_range" : "2003-2004" } ], "educations" : [ { "school" : "学校A", "date_range" : "1995-1998" }, { "school" : "学校B", "date_range" : "1995-1998" } ], "name" : "张三999999" }

mysql> select * from m_test limit 1\G
*************************** 1. row ***************************
            id: 35212
     user_info: {"name": "张三999999", "educations": [{"school": "学校A", "date_range": "1995-1998"}, {"school": "学校B", "date_range": "1995-1998"}], "work_exprs": [{"company": "公司999999", "date_range": "2001-2003"}, {"company": "公司999999999999", "date_range": "2003-2004"}], "user_basic_info": {"age": "29", "name": "张三", "address": {"city": "上海", "province": "上海"}}}

在表的字段上没有加任何索引,先根据name进行查询

mysql多次执行,去掉加载数据到内存的误差
mysql> select * from m_test where json_extract(json_extract(user_info,'$.user_basic_info'),'$.name')='张三3752028932291'; 
+-------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| id    | user_info                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
+-------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| 35213 | {"educations": [{"school": "学校A", "company": "学校3752028932291", "date_range": "1995-1998"}, {"school": "学校B", "company": "学校37520289322913752028932291", "date_range": "1995-1998"}], "work_exprs": [{"company": "公司3752028932291", "date_range": "2001-2003"}, {"company": "公司37520289322913752028932291", "date_range": "2003-2004"}], "user_basic_info": {"age": "3752028932291", "name": "张三3752028932291", "address": {"city": "上海", "province": "上海"}}}                   |
+-------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (39.03 sec)

db.test2.find({"user_basic_info.name":"张三3752028932291"})
执行近20s

可以看到这个时间上mysql就差了一倍。

下面在mysql的json字段上添加索引,对比下加了索引的情况

Create Table: CREATE TABLE `m_test` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_info` json DEFAULT NULL,
  `names_virtual2` varchar(50) GENERATED ALWAYS AS (json_extract(json_extract(`user_info`,'$.user_basic_info'),'$.name')) VIRTUAL,
  `names_virtual3` varchar(50) GENERATED ALWAYS AS (json_extract(json_extract(`user_info`,'$.user_basic_info'),'$.name')) STORED,
  PRIMARY KEY (`id`),
  KEY `idx_name3` (`names_virtual3`),
  KEY `idx_name` (`names_virtual2`)
) ENGINE=InnoDB AUTO_INCREMENT=21039616 DEFAULT CHARSET=utf8

看到加了2个虚拟列,并且创建了索引,但是我进行查询的时候,通过索引却无法找到记录,实际上是有索引的。
mysql> select * from m_test where id=35213\G
*************************** 1. row ***************************
            id: 35213
     user_info: {"educations": [{"school": "学校A", "company": "学校3752028932291", "date_range": "1995-1998"}, {"school": "学校B", "company": "学校37520289322913752028932291", "date_range": "1995-1998"}], "work_exprs": [{"company": "公司3752028932291", "date_range": "2001-2003"}, {"company": "公司37520289322913752028932291", "date_range": "2003-2004"}], "user_basic_info": {"age": "3752028932291", "name": "张三3752028932291", "address": {"city": "上海", "province": "上海"}}}
names_virtual2: "张三3752028932291"
names_virtual3: "张三3752028932291"
1 row in set (0.00 sec)

mysql>  select * from m_test where names_virtual2='张三3752028932291';
Empty set (0.00 sec)

mysql>  select * from m_test where names_virtual3='张三3752028932291';
Empty set (0.00 sec)

mysql> select * from m_test where json_extract(json_extract(`user_info`,'$.user_basic_info'),'$.name')='张三3752028932291';
+-------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------+-----------------------+
| id    | user_info                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         | names_virtual2        | names_virtual3        |
+-------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------+-----------------------+
| 35213 | {"educations": [{"school": "学校A", "company": "学校3752028932291", "date_range": "1995-1998"}, {"school": "学校B", "company": "学校37520289322913752028932291", "date_range": "1995-1998"}], "work_exprs": [{"company": "公司3752028932291", "date_range": "2001-2003"}, {"company": "公司37520289322913752028932291", "date_range": "2003-2004"}], "user_basic_info": {"age": "3752028932291", "name": "张三3752028932291", "address": {"city": "上海", "province": "上海"}}}                   | "张三3752028932291"   | "张三3752028932291"   |
+-------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------+-----------------------+
1 row in set (1 min 28.49 sec)

mongodb加了索引后,查询时间是0s

上面通过索引无法找到数据,原因是返回的是json,需要返回字符传
另外在创建store的虚拟咧上的时候,磁盘空间直接翻倍了,达到了20g,mongodb的磁盘文件大小是2.4g。
争取的使用方式是

alter table m_test add names_virtual2 varchar(50) GENERATED ALWAYS AS (user_info->>"$.user_basic_info.name") VIRTUAL;
Query OK, 0 rows affected (0.09 sec)
mysql> show create table m_test\G
*************************** 1. row ***************************
       Table: m_test
Create Table: CREATE TABLE `m_test` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_info` json DEFAULT NULL,
  `names_virtual2` varchar(50) GENERATED ALWAYS AS (json_unquote(json_extract(`user_info`,'$.user_basic_info.name'))) VIRTUAL,
  PRIMARY KEY (`id`),
  KEY `idx_name` (`names_virtual2`)
) ENGINE=InnoDB AUTO_INCREMENT=21039616 DEFAULT CHARSET=utf8

这样查询是正确的,并且查询速度也是0s

mysql>  select * from m_test where names_virtual2='张三3752028932291'\G
*************************** 1. row ***************************
            id: 35213
     user_info: {"educations": [{"school": "学校A", "company": "学校3752028932291", "date_range": "1995-1998"}, {"school": "学校B", "company": "学校37520289322913752028932291", "date_range": "1995-1998"}], "work_exprs": [{"company": "公司3752028932291", "date_range": "2001-2003"}, {"company": "公司37520289322913752028932291", "date_range": "2003-2004"}], "user_basic_info": {"age": "3752028932291", "name": "张三3752028932291", "address": {"city": "上海", "province": "上海"}}}
names_virtual2: 张三3752028932291
1 row in set (0.00 sec)

从上面的测试看,在2kw的数据量下,单个的访问json的速度是一样的。
mysql使用的磁盘容量是15g,比mongodb的磁盘消耗要大很多

发布了605 篇原创文章 · 获赞 41 · 访问量 80万+

猜你喜欢

转载自blog.csdn.net/aoerqileng/article/details/104052731