多属性、多分类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 22 MySQL
MySQL数据迁移相关总结
Apr 29 MySQL
JDBC连接的六步实例代码(与mysql连接)
May 12 MySQL
MySQL千万级数据表的优化实战记录
Aug 04 MySQL
Mysql中where与on的区别及何时使用详析
Aug 04 MySQL
关于MySQL中的 like操作符详情
Nov 17 MySQL
mysql5.6主从搭建以及不同步问题详解
Dec 04 MySQL
Mysql中有关Datetime和Timestamp的使用总结
Dec 06 MySQL
SQL基础查询和LINQ集成化查询
Jan 18 MySQL
MySQL中IO问题的深入分析与优化
Apr 02 MySQL
mysql查询结果实现多列拼接查询
Apr 03 MySQL
MySQL的意向共享锁、意向排它锁和死锁
Jul 15 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将会员数据导入到ucenter的代码
2010/07/18 PHP
Views rows style模板重写代码
2011/05/16 PHP
PHP+swoole实现简单多人在线聊天群发
2016/01/19 PHP
thinkPHP模板中函数的使用方法示例
2016/11/30 PHP
javascript学习网址备忘
2007/05/29 Javascript
jQuery通过点击行来删除HTML表格行的实现示例
2014/09/10 Javascript
JS实现5秒钟自动封锁div层的方法
2015/02/20 Javascript
浅谈Javascript的静态属性和原型属性
2015/05/07 Javascript
js获取表格的行数和列数的方法
2015/10/23 Javascript
利用jquery制作滚动到指定位置触发动画
2016/03/26 Javascript
jquery中validate与form插件提交的方式小结
2016/03/26 Javascript
AngularJs基本特性解析(一)
2016/07/21 Javascript
jquery实现input框获取焦点的方法
2017/02/06 Javascript
js鼠标移动时禁止选中文字
2017/02/19 Javascript
Vue + Webpack + Vue-loader学习教程之功能介绍篇
2017/03/14 Javascript
常用的 JS 排序算法 整理版
2018/04/05 Javascript
JavaScript实现的DOM树遍历方法详解【二叉DOM树、多叉DOM树】
2018/05/07 Javascript
vue图片上传本地预览组件使用详解
2019/02/20 Javascript
uni-app使用微信小程序云函数的步骤示例
2020/05/22 Javascript
[51:27]LGD vs Liquid 2019国际邀请赛小组赛 BO2 第二场 8.16
2019/08/19 DOTA
详解Python中的strftime()方法的使用
2015/05/22 Python
python django 增删改查操作 数据库Mysql
2017/07/27 Python
Python下载网络小说实例代码
2018/02/03 Python
python 轮询执行某函数的2种方式
2020/05/03 Python
Python爬取豆瓣数据实现过程解析
2020/10/27 Python
python从PDF中提取数据的示例
2020/10/30 Python
Django前后端分离csrf token获取方式
2020/12/25 Python
纯css3实现的动画按钮的实例教程
2014/11/17 HTML / CSS
小学生期末评语
2014/04/21 职场文书
班级年度安全计划书
2014/05/01 职场文书
护士节活动总结
2014/08/29 职场文书
2014年度个人工作总结
2014/11/07 职场文书
老公写给老婆的检讨书
2015/05/06 职场文书
企业催款函范本
2015/06/24 职场文书
tensorboard 可视化之localhost:6006不显示的解决方案
2021/05/22 Python
使用MybatisPlus打印sql语句
2022/04/22 SQL Server