多属性、多分类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 Show Profile
Apr 05 MySQL
解决Navicat for Mysql连接报错1251的问题(连接失败)
May 27 MySQL
mysql升级到5.7时,wordpress导数据报错1067的问题
May 27 MySQL
Mysql systemctl start mysqld报错的问题解决
Jun 03 MySQL
mysql 如何获取两个集合的交集/差集/并集
Jun 08 MySQL
MySQL的安装与配置详细教程
Jun 26 MySQL
MySQL子查询中order by不生效问题的解决方法
Aug 02 MySQL
MySQL定时备份数据库(全库备份)的实现
Sep 25 MySQL
记一次Mysql不走日期字段索引的原因小结
Oct 24 MySQL
VS2019连接MySQL数据库的过程及常见问题总结
Nov 27 MySQL
MySQL中一条update语句是如何执行的
Mar 16 MySQL
MySQL中一条SQL查询语句是如何执行的
Apr 08 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
什么是调频(FM)、调幅(AM)、短波(SW)、长波(LW)
2021/03/01 无线电
桌面中心(一)创建数据库
2006/10/09 PHP
php 远程关机操作的代码
2008/12/05 PHP
PHP中SESSION使用中的一点经验总结
2012/03/30 PHP
php中switch与ifelse的效率区别及适用情况分析
2015/02/12 PHP
Laravel框架中队列和工作(Queues、Jobs)操作实例详解
2020/04/06 PHP
Javascript的getYear、getFullYear、getUTCFullYear异同分享
2011/11/30 Javascript
基于jquery的时间段实现代码
2012/08/02 Javascript
JS数组去重与取重的示例代码
2014/01/24 Javascript
JS根据年月获得当月天数的实现代码
2014/07/03 Javascript
解决angular的post请求后SpringMVC后台接收不到参数值问题的方法
2015/12/10 Javascript
js仿支付宝填写支付密码效果实现多方框输入密码
2016/03/09 Javascript
详解Vue.js——60分钟组件快速入门(上篇)
2016/12/05 Javascript
原生js实现水平方向无缝滚动
2017/01/10 Javascript
JS函数内部属性之arguments和this实例解析
2018/10/07 Javascript
PHPStorm中如何对nodejs项目进行单元测试详解
2019/02/28 NodeJs
详解vue中$nextTick和$forceUpdate的用法
2019/12/11 Javascript
详解Python编程中基本的数学计算使用
2016/02/04 Python
Python编程中对super函数的正确理解和用法解析
2016/07/02 Python
python使用numpy读取、保存txt数据的实例
2018/10/14 Python
Python生成指定数量的优惠码实操内容
2019/06/18 Python
Python实现最常见加密方式详解
2019/07/13 Python
python常见字符串处理函数与用法汇总
2019/10/30 Python
Python操作Sqlite正确实现方法解析
2020/02/05 Python
Python Opencv中用compareHist函数进行直方图比较对比图片
2020/04/07 Python
python使用建议与技巧分享(一)
2020/08/17 Python
scrapy-splash简单使用详解
2021/02/21 Python
美国知名的在线旅游服务网站:Priceline
2016/07/23 全球购物
美国专业级皮肤病和spa品质护肤品的高级零售网站:SkinCareRx
2017/02/06 全球购物
沪江旗下的海量优质课程平台:沪江网校
2017/11/07 全球购物
js实现弹框效果
2021/03/24 Javascript
物业管理毕业生的自我评价
2014/02/17 职场文书
银行竞聘报告范文
2014/11/06 职场文书
收入证明范本
2015/06/12 职场文书
机械生产实习心得体会
2016/01/22 职场文书
小程序教您怎样你零成本推广获取数万用户的方法
2019/07/30 职场文书