多属性、多分类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入门命令之函数-单行函数-流程控制函数
Apr 05 MySQL
如何搭建 MySQL 高可用高性能集群
Jun 21 MySQL
浅谈mysql增加索引不生效的几种情况
Jun 23 MySQL
MySQL 十大常用字符串函数详解
Jun 30 MySQL
MySQL实例精讲单行函数以及字符数学日期流程控制
Oct 15 MySQL
SQL基础的查询语句
Nov 11 MySQL
实战 快速定位MySQL的慢SQL
Mar 22 MySQL
一文了解MYSQL三大范式和表约束
Apr 03 MySQL
MySQL创建管理RANGE分区
Apr 13 MySQL
详解Mysql数据库平滑扩容解决高并发和大数据量问题
May 25 MySQL
MySQL数据库简介与基本操作
May 30 MySQL
MySQL数据库安装方法与图形化管理工具介绍
May 30 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
PHP 变量定义和变量替换的方法
2009/07/30 PHP
让PHP显示Facebook的粉丝数量方法
2014/01/08 PHP
php 邮件发送问题解决
2014/03/22 PHP
JavaScript中出现乱码的处理心得
2009/12/24 Javascript
javascript中类的定义及其方式(《javascript高级程序设计》学习笔记)
2011/07/04 Javascript
javascript中length属性的探索
2011/07/31 Javascript
JavaScript控制Session操作方法
2013/01/17 Javascript
jquery append 动态添加的元素事件on 不起作用的解决方案
2015/07/30 Javascript
JS实现的简洁纵向滑动菜单(滑动门)效果
2015/10/19 Javascript
浅谈JavaScript异步编程
2017/01/20 Javascript
jQuery实现select下拉框获取当前选中文本、值、索引
2017/05/08 jQuery
十大 Node.js 的 Web 框架(快速提升工作效率)
2017/06/30 Javascript
Vue实现一个返回顶部backToTop组件
2017/07/25 Javascript
vue编译打包本地查看index文件的方法
2018/02/23 Javascript
小程序分享模块超级详解(推荐)
2019/04/10 Javascript
[43:35]EG vs Winstrike 2018国际邀请赛小组赛BO2 第一场 8.18
2018/08/19 DOTA
Python在Console下显示文本进度条的方法
2016/02/14 Python
详解python eval函数的妙用
2017/11/16 Python
Scrapy框架CrawlSpiders的介绍以及使用详解
2017/11/29 Python
dataframe设置两个条件取值的实例
2018/04/12 Python
Python面向对象基础入门之编码细节与注意事项
2018/12/11 Python
利用python画出AUC曲线的实例
2020/02/28 Python
python破解同事的压缩包密码
2020/10/14 Python
CSS3 border-image详解、应用及jQuery插件
2011/08/29 HTML / CSS
非凡女性奢华谦虚风格:The Modist
2017/10/28 全球购物
印度化妆品购物网站:Nykaa
2018/07/22 全球购物
教师自我评价范例
2013/09/24 职场文书
电大学习个人自我评价范文
2013/10/04 职场文书
人身损害赔偿协议书范本
2014/09/27 职场文书
公司介绍信范文
2015/01/31 职场文书
施工安全员岗位职责
2015/04/11 职场文书
黑暗中的舞者观后感
2015/06/18 职场文书
2015年社区重阳节活动总结
2015/07/30 职场文书
《老人与海鸥》教学反思
2016/02/16 职场文书
详解JavaScript中Arguments对象用途
2021/08/30 Javascript
python人工智能human learn绘图可创建机器学习模型
2021/11/23 Python