多属性、多分类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的客户端和服务端协议
May 10 MySQL
为什么mysql字段要使用NOT NULL
May 13 MySQL
MySQL系列之十三 MySQL的复制
Jul 02 MySQL
mysql分表之后如何平滑上线详解
Nov 01 MySQL
MySQL对数据表已有表进行分区表的实现
Nov 01 MySQL
MYSQL 表的全面总结
Nov 11 MySQL
关于MySQL中的 like操作符详情
Nov 17 MySQL
如何避免mysql启动时错误及sock文件作用分析
Jan 22 MySQL
MYSQL常用函数介绍
May 05 MySQL
mysql查找连续出现n次以上的数字
May 11 MySQL
MySQL脏读,幻读和不可重复读
May 11 MySQL
MySQL主从切换的超详细步骤
Jun 28 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
Ping服务的php实现方法,让网站快速被收录
2012/02/04 PHP
基于PHP常用字符串的总结(待续)
2013/06/07 PHP
php metaphone()函数的定义和用法
2016/05/15 PHP
解决PHP程序运行时:Fatal error: Maximum execution time of 30 seconds exceeded in的错误提示
2016/11/25 PHP
CakePHP框架Model关联对象用法分析
2017/08/04 PHP
IE6下通过a标签点击切换图片的问题
2010/11/14 Javascript
JavaScript 继承使用分析
2011/05/12 Javascript
JSON 数据格式介绍
2012/01/13 Javascript
JavaScript设计模式之外观模式实例
2014/10/10 Javascript
jQuery DOM删除节点操作指南
2015/03/03 Javascript
JavaScript各类型的关系图解
2015/10/16 Javascript
基于BootStrap与jQuery.validate实现表单提交校验功能
2016/12/22 Javascript
kafka调试中遇到Connection to node -1 could not be established. Broker may not be available.
2019/09/17 Javascript
关于Node.js中频繁修改代码重启服务器的问题
2020/10/15 Javascript
ES5和ES6中类的区别总结
2020/12/21 Javascript
python查找第k小元素代码分享
2013/12/18 Python
跟老齐学Python之集合的关系
2014/09/24 Python
Django中ORM表的创建和增删改查方法示例
2017/11/15 Python
详解Python nose单元测试框架的安装与使用
2017/12/20 Python
对Python Class之间函数的调用关系详解
2019/01/23 Python
python3发送request请求及查看返回结果实例
2020/04/30 Python
使用opencv识别图像红色区域,并输出红色区域中心点坐标
2020/06/02 Python
解决python中0x80072ee2错误的方法
2020/07/19 Python
python3.5的包存放的具体路径
2020/08/16 Python
Arti-shopping中文官网:大型海外商品一站式直邮平台
2020/03/23 全球购物
环境科学专业大学生自荐信格式
2013/09/21 职场文书
公司活动策划方案
2014/01/13 职场文书
转预备党员政审材料
2014/02/06 职场文书
公司合作协议书范本
2014/04/18 职场文书
活动倡议书范文
2014/05/13 职场文书
商场周年庆活动方案
2014/08/19 职场文书
党的群众路线对照检查材料
2014/09/22 职场文书
2014年除四害工作总结
2014/12/06 职场文书
队列队形口号
2015/12/25 职场文书
《狼王梦》读后感:可怜天下父母心
2019/11/01 职场文书
常用的Python代码调试工具总结
2021/06/23 Python