多属性、多分类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 08 MySQL
MySQL8.0无法启动3534的解决方法
Jun 03 MySQL
MySQL 亿级数据导入导出及迁移笔记
Jun 18 MySQL
MySQL系列之十五 MySQL常用配置和性能压力测试
Jul 02 MySQL
深入解析MySQL索引数据结构
Oct 16 MySQL
VS2019连接MySQL数据库的过程及常见问题总结
Nov 27 MySQL
Mysql数据库表中为什么有索引却没有提高查询速度
Feb 24 MySQL
MYSQL如何查看进程和kill进程
Mar 13 MySQL
一条 SQL 语句执行过程
Mar 17 MySQL
Mysql 如何合理地统计一个数据库里的所有表的数据量
Apr 18 MySQL
MYSQL中文乱码问题的解决方案
Jun 14 MySQL
MySQL一劳永逸永久支持输入中文的方法实例
Aug 05 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
咖啡与水的关系
2021/03/03 冲泡冲煮
php正则过滤html标签、空格、换行符的代码(附说明)
2010/10/25 PHP
apache+codeigniter 通过.htcaccess做动态二级域名解析
2012/07/01 PHP
PHP高手需要要掌握的知识点
2014/08/21 PHP
php链表用法实例分析
2015/07/09 PHP
thinkPHP自定义类实现方法详解
2016/11/30 PHP
CI(CodeIgniter)框架中URL特殊字符处理与SQL注入隐患分析
2019/02/28 PHP
php给数组赋值的实例方法
2019/09/26 PHP
Javascript实例教程(19) 使用HoTMetal(2)
2006/12/23 Javascript
js实现网页随机切换背景图片的方法
2014/11/01 Javascript
javascript+HTML5的canvas实现七夕情人节3D玫瑰花效果代码
2015/08/04 Javascript
JavaScript实现删除,移动和复制文件的方法
2015/08/05 Javascript
JavaScript的MVVM库Vue.js入门学习笔记
2016/05/03 Javascript
Vue filters过滤器的使用方法
2017/07/14 Javascript
详解webpack中的hash、chunkhash、contenthash区别
2018/01/05 Javascript
React之PureComponent的使用作用
2018/07/10 Javascript
2种在vue项目中使用百度地图的简单方法
2018/09/28 Javascript
微信小程序select下拉框实现效果
2019/05/15 Javascript
浅谈一种让小程序支持JSX语法的新思路
2019/06/16 Javascript
JS this关键字在ajax中使用出现问题解决方案
2020/07/17 Javascript
js实现日历
2020/11/07 Javascript
Python实现的二维码生成小软件
2014/07/11 Python
Python绘制3d螺旋曲线图实例代码
2017/12/20 Python
python pygame实现2048游戏
2018/11/20 Python
基于python监控程序是否关闭
2020/01/14 Python
TensorFlow tensor的拼接实例
2020/01/19 Python
3种适用于Python的疯狂秘密武器及原因解析
2020/04/29 Python
IE滤镜与CSS3效果(详细整理分享)
2013/01/25 HTML / CSS
简述DNS进行域名解析的过程
2013/12/02 面试题
幼儿发展评估方案
2014/06/11 职场文书
宣传口号大全
2014/06/16 职场文书
学生保证书格式
2015/02/27 职场文书
培根随笔读书笔记
2015/07/01 职场文书
2015年四年级班主任工作总结
2015/10/22 职场文书
如何用python插入独创性声明
2021/03/31 Python
HTML实现仿Windows桌面主题特效的实现
2022/06/28 HTML / CSS