多属性、多分类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 Innodb关键特性之插入缓冲(insert buffer)
Apr 08 MySQL
将图片保存到mysql数据库并展示在前端页面的实现代码
May 02 MySQL
MySQL sql_mode的使用详解
May 08 MySQL
mysql 8.0.24版本安装配置方法图文教程
May 12 MySQL
IDEA 链接Mysql数据库并执行查询操作的完整代码
May 20 MySQL
MySQL 查询速度慢的原因
May 25 MySQL
MYSQL主从数据库同步备份配置的方法
May 26 MySQL
MySQL非空约束(not null)案例讲解
Aug 23 MySQL
mysql分组后合并显示一个字段的多条数据方式
Jan 22 MySQL
Mysql 文件配置解析介绍
May 06 MySQL
MySQL 逻辑备份 into outfile
May 15 MySQL
mysql数据库如何转移到oracle
Dec 24 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
Terran魔法科技
2020/03/14 星际争霸
php实现快速排序法函数代码
2012/08/27 PHP
用PHP实现弹出消息提示框的两种方法
2013/12/17 PHP
详解将数据从Laravel传送到vue的四种方式
2019/10/16 PHP
ASP中进行HTML数据及JS数据编码函数
2009/11/11 Javascript
原创javascript小游戏实现代码
2010/08/19 Javascript
jquery中ajax学习笔记一
2011/10/16 Javascript
浅析JavaScript中的typeof运算符
2013/11/30 Javascript
快速解决jQuery与其他库冲突的方法介绍
2014/01/02 Javascript
window.location.href的用法(动态输出跳转)
2014/08/09 Javascript
jQuery获取checkbox选中的值
2016/01/28 Javascript
jQuery 3.0十大新特性
2016/07/06 Javascript
canvas 绘制圆形时钟
2017/02/22 Javascript
JavaScript中最常见的三个面试题解析
2017/03/04 Javascript
Windows下Node爬虫神器Puppeteer安装记
2019/01/09 Javascript
angular使用md5,CryptoJS des加密的方法
2019/06/03 Javascript
微信小程序npm引入vant-weapp的踩坑记录
2019/08/01 Javascript
python搭建简易服务器分析与实现
2012/12/15 Python
python不带重复的全排列代码
2013/08/13 Python
python虚拟环境virtualenv的安装与使用
2017/09/21 Python
python操作excel的包(openpyxl、xlsxwriter)
2018/06/11 Python
Python利用递归实现文件的复制方法
2018/10/27 Python
对pyqt5之menu和action的使用详解
2019/06/20 Python
python并发编程多进程 模拟抢票实现过程
2019/08/20 Python
python打印直角三角形与等腰三角形实例代码
2019/10/20 Python
使用pandas 将DataFrame转化成dict
2019/12/10 Python
解决PDF 转图片时丢文字的一种可能方式
2021/03/04 Python
廉价航班、机票和酒店:JustFly
2018/02/07 全球购物
Optimalprint加拿大:在线打印服务
2020/04/03 全球购物
Sony C++笔试题
2013/03/10 面试题
开平碉楼导游词
2015/02/06 职场文书
医院财务人员岗位职责
2015/04/14 职场文书
清明节主题班会
2015/08/14 职场文书
2016年公司“3.12”植树节活动总结
2016/03/16 职场文书
Java tomcat手动配置servlet详解
2021/11/27 Java/Android
详解SQL的窗口函数
2022/04/21 Oracle