多属性、多分类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 14 MySQL
MYSQL(电话号码,身份证)数据脱敏的实现
May 28 MySQL
MySQL系列之五 视图、存储函数、存储过程、触发器
Jul 02 MySQL
MySQL深度分页(千万级数据量如何快速分页)
Jul 25 MySQL
为什么MySQL分页用limit会越来越慢
Jul 25 MySQL
MySQL中连接查询和子查询的问题
Sep 04 MySQL
JMeter对MySQL数据库进行压力测试的实现步骤
Jan 22 MySQL
分享MySQL常用 内核 Debug 几种常见方法
Mar 17 MySQL
详细聊一聊mysql的树形结构存储以及查询
Apr 05 MySQL
手把手带你彻底卸载MySQL数据库
Jun 14 MySQL
MySQL提升大量数据查询效率的优化神器
Jul 07 MySQL
MySQL下载安装配置详细教程 附下载资源
Sep 23 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
用js进行url编码后用php反解以及用php实现js的escape功能函数总结
2010/02/08 PHP
PHP 图片文件上传实现代码
2010/12/29 PHP
PHP获取MSN好友列表类的实现代码
2013/06/23 PHP
Zend Framework动作助手(Zend_Controller_Action_Helper)用法详解
2016/03/05 PHP
Yii2 GridView实现列表页直接修改数据的方法
2016/05/16 PHP
为调试JavaScript添加输出窗口的代码
2010/02/07 Javascript
JQuery 文本框使用小结
2010/05/22 Javascript
XMLHTTPRequest的属性和方法简介
2010/11/23 Javascript
jquery解决图片路径不存在执行替换路径
2013/02/06 Javascript
Nodejs中的this详解
2016/03/26 NodeJs
谈谈Vue.js——vue-resource全攻略
2017/01/16 Javascript
JavaScript实现前端分页控件
2017/04/19 Javascript
浅谈ES6 模板字符串的具体使用方法
2017/11/07 Javascript
vue-cli配置环境变量的方法
2018/07/09 Javascript
微信{"errcode":48001,"errmsg":"api unauthorized, hints: [ req_id: 1QoCla0699ns81 ]"}
2018/10/12 Javascript
Vue项目history模式下微信分享爬坑总结
2019/03/29 Javascript
微信小程序实现禁止分享代码实例
2019/10/19 Javascript
WebStorm无法正确识别Vue3组合式API的解决方案
2021/02/18 Vue.js
[02:40]DOTA2英雄基础教程 先知
2013/11/29 DOTA
在Django的URLconf中使用多个视图前缀的方法
2015/07/18 Python
python 实现一次性在文件中写入多行的方法
2019/01/28 Python
Python hashlib模块加密过程解析
2019/11/05 Python
python实现串口通信的示例代码
2020/02/10 Python
Python2.7:使用Pyhook模块监听鼠标键盘事件-获取坐标实例
2020/03/14 Python
Python PyQt5运行程序把输出信息展示到GUI图形界面上
2020/04/27 Python
Keras 切换后端方式(Theano和TensorFlow)
2020/06/19 Python
SQL注入攻击的种类有哪些
2013/12/30 面试题
生产车间班组长岗位职责
2014/01/06 职场文书
《影子》教学反思
2014/02/21 职场文书
80后职场人的职业生涯规划
2014/03/08 职场文书
个人收入证明范本
2014/09/18 职场文书
挂靠协议书
2015/01/27 职场文书
庐山导游词
2015/02/03 职场文书
全陪导游词
2015/02/04 职场文书
一文搞懂Python Sklearn库使用
2021/08/23 Python
Python学习之时间包使用教程详解
2022/03/21 Python