多属性、多分类MySQL模式设计


Posted in MySQL onApril 05, 2021

0、导读

这是来自B乎的一个问答。
当数据同时具备多个属性/分类时,改如何设计表结构和查询?

1、需求描述

我偶尔也会逛逛B乎,看到一些感兴趣的话题也会回复下。
有一次,看到这样的一个话题:

链接:https://www.zhihu.com/question/337083976/answer/767075575

 

[mysql] 当数据同时属于多个分类时,该怎么查询?

分类cate字段为[1,2,3,4,5] ,假如要查询满足分类'2'和'5' 的数据该怎么查询?
我尝试过用 cate like '%2%' AND cate like '%5%'去查。
想问有没有更好的办法,我这样写数据少了还好,多了根本没法查,效率太低了。

恰好我以前做过类似的业务需求设计,所以就回复了这个问题。

2、模式设计思路

这个需求可以有几种不同的解决思路,我们分别展开说一下。

2.1 用bit数据类型

大概思路如下:
1、物品属性列c1 用bit数据类型 来表示,也就是只有0、1两种取值
2、当物品属性具备某个分类属性时,其值为1,否则为0
3、假如共有5个分类,当物品拥有全部分类属性时,则其值为11111,若其不具备第3个分类属性,则其值为11011,在数据库中转成十进制存储
4、上述两种情况下,将二进制转换成十进制表示,即分别是31和27(建议横版观看,可左右滑动

[root@yejr.me] [zhishutang]> select conv(11111, 2, 10), conv(11011, 2, 10);
+--------------------+--------------------+
| conv(11111, 2, 10) | conv(11011, 2, 10) |
+--------------------+--------------------+
| 31                 | 27                 |
+--------------------+--------------------+

5、然后,只需要对该列用十进制值进行查询比对就行
6、现在如果想判断是否同时具备2、5两个分类属性时,其二进制表示为01001,转成十进制为9,只需要用条件 where c1=9 即可

我们来演示一下:(建议横版观看,可左右滑动

[root@yejr.me] [zhishutang]>show create table t_bit\G
*************************** 1. row ***************************
       Table: t_bit
Create Table: CREATE TABLE `t_bit` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `c1` int(10) unsigned NOT NULL DEFAULT '0',
  `c2` varchar(10) NOT NULL DEFAULT '',
  PRIMARY KEY (`id`),
  KEY `c1` (`c1`)
) ENGINE=InnoDB;

insert into t_bit select 0,conv(00001, 2, 10), 'item1';
insert into t_bit select 0,conv(00011, 2, 10), 'item2';
insert into t_bit select 0,conv(00111, 2, 10), 'item3';
insert into t_bit select 0,conv(01111, 2, 10), 'item4';
insert into t_bit select 0,conv(11111, 2, 10), 'item5';
insert into t_bit select 0,conv(10111, 2, 10), 'item6';
insert into t_bit select 0,conv(11011, 2, 10), 'item7';
insert into t_bit select 0,conv(11101, 2, 10), 'item8';
insert into t_bit select 0,conv(11110, 2, 10), 'item9';

[root@yejr.me] [zhishutang]>select * from t_bit;
+----+----+-------+
| id | c1 | c2    |
+----+----+-------+
|  1 |  1 | item1 |
|  2 |  3 | item2 |
|  3 |  7 | item3 |
|  4 | 15 | item4 |
|  5 | 31 | item5 |
|  6 | 23 | item6 |
|  7 | 27 | item7 |
|  8 | 29 | item8 |
|  9 | 30 | item9 |
+----+----+-------+

[root@yejr.me] [zhishutang]>select * from t_bit where c1 = conv(11011,2,10);
+----+----+-------+
| id | c1 | c2    |
+----+----+-------+
|  7 | 27 | item7 |
+----+----+-------+

# 同时我们也注意到这个SQL是可以正常使用索引的
[root@yejr.me] [zhishutang]>desc select * from t_bit where c1 = conv(11011,2,10)\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: t_bit
   partitions: NULL
         type: ref
possible_keys: c1
          key: c1
      key_len: 4
          ref: const
         rows: 1
     filtered: 100.00
        Extra: NULL

下面两种方法是B乎网友的回复,大家也可以参考下。

  1. 用JSON数据类型,然后利用JSON_CONTAINS()函数进行查询

  2. 用SET数据类型,然后利用FIND_IN_SET()函数进行查询

不过,JSON和SET这两种数据类型都不方便加索引以及利用索引扫描,即便是用了5.7的JSON+虚拟列功能,索引效率也是比较低的。而支持JSON数据类型 多值索引(multi-valued Indexes) 也要8.0.17 以上版本才支持。

3、总结

这样看来,总的来说,用二进制转十进制方式来解决本案例需求更为高效,也欢迎提出更多方案思路。

延伸阅读

  • Multi-Valued Indexes,https://dev.mysql.com/doc/refman/8.0/en/create-index.html#create-index-multi-valued

  • The SET Type,https://dev.mysql.com/doc/refman/8.0/en/set.html

Enjoy MySQL :)

MySQL 相关文章推荐
详解MySQL的Seconds_Behind_Master
May 18 MySQL
详解Mysql和Oracle之间的误区
May 18 MySQL
MySQL中存储时间的最佳实践指南
Jul 01 MySQL
MySQL高速缓存启动方法及参数详解(query_cache_size)
Jul 01 MySQL
Mysql实现简易版搜索引擎的示例代码
Aug 30 MySQL
MySQL的InnoDB存储引擎的数据页结构详解
Mar 03 MySQL
Golang连接并操作MySQL
Apr 14 MySQL
优化Mysql查询的示例
Apr 26 MySQL
MySQL脏读,幻读和不可重复读
May 11 MySQL
mysql5.5中文乱码问题解决的有用方法
May 30 MySQL
关于mysql中string和number的转换问题
Jun 14 MySQL
MySQL新手入门进阶语句汇总
Sep 23 MySQL
多表查询、事务、DCL
Mysql Show Profile
Apr 05 #MySQL
Mysql - 常用函数 每天积极向上
Apr 05 #MySQL
mysql多表查询-笔记七
Apr 05 #MySQL
mysql部分操作
Apr 05 #MySQL
left join、inner join、right join的区别
数据库的高级查询六:表连接查询:外连接(左外连接,右外连接,UNION关键字,连接中ON与WHERE的不同)
You might like
Syphon 使用方法
2021/03/03 冲泡冲煮
一个查看session内容的函数
2006/10/09 PHP
php递归实现无限分类的方法
2015/07/28 PHP
2款PHP无限级分类实例代码
2015/11/11 PHP
qTip 基于JQuery的Tooltip插件[兼容性好]
2010/09/01 Javascript
JavaScript对象之间的转换 jQuery对象和原声DOM
2011/03/07 Javascript
使用jQuery将多条数据插入模态框的实现代码
2014/10/08 Javascript
深入剖析JavaScript:Object类型
2016/05/10 Javascript
用AngularJS的指令实现tabs切换效果
2016/08/31 Javascript
Javascript动画效果(1)
2016/10/11 Javascript
ionic cordova一次上传多张图片(类似input file提交表单)的实现方法
2016/12/16 Javascript
详解Angular 4 表单快速入门
2017/06/05 Javascript
谈谈JS中的!!
2017/12/07 Javascript
详解使用mpvue开发github小程序总结
2018/07/25 Javascript
浅谈微信页面入口文件被缓存解决方案
2018/09/29 Javascript
vue 使用vue-i18n做全局中英文切换的方法
2018/10/29 Javascript
JS删除String里某个字符的方法
2021/01/06 Javascript
vue 实现强制类型转换 数字类型转为字符串
2019/11/07 Javascript
[52:09]2014 DOTA2华西杯精英邀请赛 5 25 NewBee VS DK第二场
2014/05/26 DOTA
python 切片和range()用法说明
2013/03/24 Python
Python实现配置文件备份的方法
2015/07/30 Python
对python的文件内注释 help注释方法
2018/05/23 Python
解决python3读取Python2存储的pickle文件问题
2018/10/25 Python
Python pandas.DataFrame 找出有空值的行
2019/09/09 Python
史上最详细的Python打包成exe文件教程
2021/01/17 Python
史泰博(Staples)中国官方网站:办公用品一站式采购
2016/09/05 全球购物
荷兰电脑专场:Paradigit
2018/05/05 全球购物
全球性的在线鞋类品牌:Public Desire
2019/04/03 全球购物
拓展培训心得体会
2014/01/04 职场文书
人力资源主管职责范本
2014/03/05 职场文书
项目经理任命书
2014/06/04 职场文书
大学生档案自我鉴定(2篇)
2014/10/14 职场文书
第一节英语课开场白
2015/06/01 职场文书
《水上飞机》教学反思
2016/02/20 职场文书
市直属机关2016年主题党日活动总结
2016/04/05 职场文书
java开发双人五子棋游戏
2022/05/06 Java/Android