MySQL中JSON字段的使用技巧
mysql5.7.8之后开始原生支持json. 在类似mongodb这种nosql数据库中,json存储数据是非常自然的, 在mysql中合理的使用json,能够带来极大的便利
Json字段的使用场景
在读laravel手册举例子时,我们经常会看到 $user->is_admin
来判断用户是否为管理员,但是在用户表中,admin往往只占很小一部分.如果单开一个is_admin字段是很没有必要的行为.数据库中会有大量的无意义数据存储, 我们可以为user表创建一个 json 字段,来存储我们的is_admin字段
[
{
id: 1,
username: 'weiwenhao',
rest: { // 冗余字段
is_admin: 1
}
},
{
id: 2,
username: 'eienao',
rest: null
}
]
复制代码
当然即使不使用json,我们也不会使用is_admin来判断是否为管理员.
可以通过新增admin表或者RABC来标志管理员
依旧是用户表, 很常见的一个需求是第三方登录,如果我们使直接在user表新增facebook_id,facebook_email,facebook_phone_number,google_id,....
字段, 可以预见这会造成大量的无意义数据(即使他们不占用内存,或者影响性能)
一种解决办法是 使用一对多关系来解决, 既建立一个 第三方登录表来存储第三方登录的id/email/phone_number等
但是我更喜欢使用json字段来解决这个问题
[
{
id: 1,
username: 'weiwenhao',
rest: {
is_admin: 1,
facebook_id: 2348234,
facebook_phone_number: 2834723234,
}
},
{
id: 2,
username: 'eienao',
rest: {
google_id: 2348234,
google_email: xxx@gmail.com
}
}
]
复制代码
可以看出,使用json字段使数据表的设计更加自然,集中,业务也相应的更加的简单方便.
Json字段在laravel中的使用
首先是迁移文件 $table->json('rest')->nullable();
laravel对json的使用进行了一定的优化,对于更新和创建我们可以.
$user = new User;
$user->{'rest->google_id'} = 'xxx';
# 如果你的rest字段为null,那么上面的操作会使 null 会变成 {google_id: "xxx"}, 不需要再做 是否为null的判定啦
# 如果仅使用上面的插入操作,也不需要在使用模型的修改器来吧 json => array, array => json啦
复制代码
当rest字段的值为null时,批量操作无法执行, 类似
update(['rest->google_id' => 'xxx'])
这样的操作执行无效,因此更推荐上面的方式来进行更新操作
对于查找操作可以方便的使用
User::where('rest->google_id','xxx')->firstOrFail()
关于检索的效率问题,在后面内容中给出解决方案
Generated Column (生成列)
5.7新增了生成列, 生成列的值是根据列定义中包含的表达式计算得来.官方示例:计算直角三角形的斜边的长度
CREATE TABLE triangle (
sidea DOUBLE,
sideb DOUBLE,
sidec DOUBLE AS (SQRT(sidea * sidea + sideb * sideb)) # AS (expression) 为生成列的核心语法
);
INSERT INTO triangle (sidea, sideb) VALUES(1,1),(3,4),(6,8);
# 对于上面的插入,查询可以得到如下结果
mysql> SELECT * FROM triangle;
+-------+-------+--------------------+
| sidea | sideb | sidec |
+-------+-------+--------------------+
| 1 | 1 | 1.4142135623730951 |
| 3 | 4 | 5 |
| 6 | 8 | 10 |
+-------+-------+--------------------+
复制代码
上面的 sidec的值 是根据sidea和sideb计算得来, 并未实际的存储在磁盘中.mysql5.7之前我们想要实现上面的需求可能会这样写sql语句
SELECT *,(SQRT(sidea * sidea + sideb * sideb)) as sidec FROM triangle;
复制代码
上面既生成列的主要作用, 实际上生成列有两种子类型,上面的例子属于 virtual (虚拟) 类型的生成列, 其并没有将sidec的值实际存储在磁盘中.
除了virtual, 生成列还支持 stored类型,其创建语句为
#...
sidec DOUBLE AS (SQRT(sidea * sidea + sideb * sideb)) STORED # stored不指定则默认为 virtual
#...
复制代码
当行创建或者更新时, 会重新计算 sidec并将其存储在磁盘中
生成列的另一个重要的特性是可以根据生成列表达式的计算结果建立索引. 其建立索引的方式和普通字段创建索引的方式一致.1
CREATE TABLE triangle (
sidea DOUBLE,
sideb DOUBLE,
sidec DOUBLE AS (SQRT(sidea * sidea + sideb * sideb)) # AS (expression) 为生成列的核心语法
INDEX(`sidec`)
);
复制代码
索引本身也是存储在磁盘中的实际存在的物质, 因此 virtual 生成列 + 索引,可以达到存储空间的最有效利用.
对于stored 生成列 + 索引, 通常不会访问到存储在磁盘中stored 生成列,而是直接访问索引.因此没有必要使用stored生成列
使用生成列为json中的字段添加索引
已user表的rest.google_id为例,建表操作
#...
`rest` json NULL,
# JSON_EXTRACT(`rest`,'$.google_id') 等价于 `rest`->'$.google_id'
# 5.7.13版本后
# JSON_UNQUOTE(JSON_EXTRACT(`rest`,'$.google_id')) 等价于 `rest`->>'$.google_id'
# 使用生成列为json添加索引时,请务必使用 JSON_UNQUOTE(JSON_EXTRACT(`rest`,'$.google_id'))/->>
`google_id` varchar GENERATED ALWAYS AS (`rest`->>'$.google_id')) NULL
UNIQUE INDEX(`google_id`)
#...
复制代码
在laravel迁移文件中
$table->json('rest')->nullable();
$table->string('rest')->nullable()->unique()->virtualAs('`oauth`->>"$.google_id"');
复制代码
有了索引后,当我们执行查询操作
select * from users where `rest`->'$.google_id' = 'xxx' # 通常使用这种更加简单的形式
select * from users where `rest`->>'$.google_id' = 'xxx'
# 上面两种表达式会被mysql的优化器在查询阶段自动优化为 select * from users where google_id = 'xxx'
复制代码
一些补充
virtualAs(oauth->"$.google_id"');
使用 **->**符号来创建生成列会出现无法使用索引的情况, 原因不是很明了,需要继续研究一下手册. 另外对于创建语句GENERATED ALWAYS
的作用也不是很明了.关于null, 经常会看到一种言论是mysql中使用null作为字段默认值会出现无法索引的情况.但经过查询了解,发现这是一种老中医理论. 我更倾向于使用null作为默认值, 而不是 ''/0/0.0 ,我认为null的表达性更好, laravel中也无时无刻不在提现这种思想.
关于json的使用, 最近的项目中,我大部分核心表都有一个json字段,做一些非核心数据的存储和冗余. 比
作者:weiwenhao
链接:https://juejin.im/post/5c1332625188251e663eb925
MySQL中JSON字段的使用技巧的更多相关文章
- mybatis&plus系列------Mysql的JSON字段的读取和转换
mybatis&plus系列------Mysql的JSON字段的读取和转换 一. 背景 在平常的开发中,我们可能会有这样的需求: 业务数据在存储的时候,并不是以mysql中的varchar丶 ...
- mysql中判断字段为空
mysql中判断字段为null或者不为null 在mysql中,查询某字段为空时,切记不可用 = null, 而是 is null,不为空则是 is not null select nulco ...
- 【mysql】在mysql中更新字段的部分值,更新某个字符串字段的部分内容
在mysql中更新字段的部分值,更新某个字符串字段的部分内容 sql语句如下: update goods set img = REPLACE(img,'http://ozwm3lwui.bkt.clo ...
- mysql中时间字段datetime怎么判断为空和不为空
mysql中时间字段datetime怎么判断为空和不为空一般为空都用null表示,所以一句sql语句就可以.select * from 表名 where 日期字段 is null;这里要注意null的 ...
- PG 中 JSON 字段的应用
13 年发现 pg 有了 json 类型,便从 oracle 转 pg,几年下来也算比较熟稔了,总结几个有益的实践. 用途一:存储设计时无法预料的文档性的数据.比如,通常可以在人员表准备一个 json ...
- EF架构~mysql中时间戳字段被认为是主键自增
回到目录 如果在mysql中添加了自增字段,用来维护行的版本,那么在EF中会有一个问题,会把它当成是数据表主键,当你的真正主键是自曾时,就会把默认值0拼到生成的SQL语句里,导致你的insert出错, ...
- MySQL中 指定字段排序函数field()的用法
MySQL中的field()函数,可以用来对SQL中查询结果集进行指定顺序排序. 函数使用格式如下: order by (str,str1,str2,str3,str4……),str与str1,str ...
- mysql中查询字段为null或者不为null的sql语句怎么写?
在mysql中,查询某字段为空时,切记不可用 = null,而是 is null,不为空则是 is not null select * from table where column is null; ...
- mysql中一个字段升序,另一个字段降序
mySql中,升序为asc,降序为desc.例如: 升序:select * from 表名 order by 表中的字段 asc(mysql中默认是升序排列,可不写) 降序:select ...
随机推荐
- 解决将easyui里的combobox里的输入框下拉列表变为空值
jQuery easyui官网上有一个方法是 :clear方法,这个方法说是能清除数据,但我测试了,结果它确实清楚了(但他清除的只是输入框显示的数据,没有清除所有的数据),在这里巧妙的用 它加载数据的 ...
- 微信小程序 功能函数 手机号验证*
// 登录手机验证 loginPhone: function (e) { var phone = e.detail.value; if (!(/^1[34578]\d{9}$/.test(phone) ...
- uva 11525(线段树)
题目链接:http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem& ...
- [C/C++] multimap查找一个key对应的多个value
在multimap中,同一个键关联的元素必然相邻存放.基于这个事实,就可以将某个键对应的值一一输出. 1.使用find和count函数.count函数求出某个键出现的次数,find函数返回一个迭代器, ...
- delphi开发学习四:TClientDataSet与TDataSetProvider控件使用实例
1.TClientDataSet控件 通过TClientDataSet控件可以建立瘦客户端的应用程序,且数据执行效率较高,但它不能和数据库自动连接,程序中必须制定它如何获取数据.一般情况下,TClie ...
- 【Learning】积性函数前缀和——洲阁筛(min_25写法)
问题描述 洲阁筛解决的问题主要是\(n\)范围较大的积性函数前缀和. 已知一积性函数\(f(i)\),求\(\sum_{i=1}^nf(i)\). \(n\leq10^{12}\). 求解方法 如 ...
- 【uoj125】 NOI2013—书法家
http://uoj.ac/problem/125 (题目链接) 题意 在网格上写“NOI”,每个格子上有一些权值,要求覆盖的权值最大.书写有一些规则. Solution 将“NOI”分成11个部分, ...
- 一次ajax请求导致status为canceled的原因小记
偶然碰到一个小Bug ajax请求执行后返回了一个canceled(状态码) 但是后台却接受了参数并且执行成功0.0 刚看到这个状态的时候是一脸懵逼的.... 之前并没见过这样的状态码 经过参数确认并 ...
- R kernel for Jupyter Notebook 支持r
1/2) Installing via supplied binary packages(default on Windows + Mac OS X) You can install all pack ...
- Hadoop生态圈-Hbase的rowKey设计原则
Hadoop生态圈-Hbase的rowKey设计原则 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任.