请问,如果需要 MySQL 存储几百个二进制位的数据,该用什么类型

66 天前
 awesomePower

举个例子,有一类数据,它大概有几百多种属性,属性的正好也只有 0 和 1 这两种可能。

在这种情况下,应该挑选哪个类型的字段来存储这个数据呢?需要满足以下条件:

  1. 空间占用尽量小
  2. 需要方便查询,比如我需要筛选出第 5 个、第 77 个、第 100 个属性...是 1 的数据(同时是 1 或者其中有一个是 1 这两种情况都需要查询)
  3. 用多个 BIGINT 存储可行么
2112 次点击
所在节点    程序员
16 条回复
yangg
66 天前
你存属性为啥 描述是第 5 个,第 77 个,而不是属性 a ,属性 b ?,后面这种属性直接存 json
yangg
66 天前
哦,明白了, 多个 BIGINT 也可以, 就是不直观,你不赚麻烦也可以
just1
66 天前
bool?
akira
66 天前
你可以看一下 set 和 bitmap
jy28520
66 天前
用 JSON 格式,检索的时候直接按照键查询为 1 的
mainjzb
66 天前
WHERE
field&1<<5 >0 &&
field&1<<77 >0 &&
field&1<<100 >0
hiboshi
66 天前
能不能将这些数据位图化看看能不能解决,创建一个字段类型是 blob , 关键词: mysql bitmap
gainsurier
66 天前
> 用多个 BIGINT 存储可行么
可行,field1 ,field2 ,field3......
dode
66 天前
使用 id,type,value 数据库增加一个属性列,简单明了,查询方便
vibbow
66 天前
@mainjzb 这么查就是性能地狱...
wellerman
65 天前
用多个字段存代价太大,这类属性大概还会动态增加,维护太不划算了。

只用一个 string 字段就行,存成 1-0,3-1,4-0,5-1,22-0,77-1,100-1 等,后面想要增加也不用动数据库。

查询条件 FIND_IN_SET('5-1', attrs) and FIND_IN_SET('77-1', attrs) and FIND_IN_SET('100-1', attrs)

或者如楼上,增加一个属性表。
ntedshen
65 天前
bigint 我之前测试过四五个属性的情况,可行而且位运算的性能在我这里比 mariadb 的 set 还优秀一些。。。
就是维护比较地狱。。。
也没测过几百个会是什么情况。。。

find_in_set 我现在会用来存一些标签但是性能确实太不好看了,最近正在切到 json 。。。
sagaxu
65 天前
存储用多个 BIGINT 可以,查但询很麻烦。如果检索条件是这些 bits ,用 mysql 不太适合,每次都扫全表 100 万行就不行了,这种要上搜索引擎。
Donjote
64 天前
好像容易出现慢 sql 。
SQL: SELECT COUNT(1) FROM attendance_daily_report_08 WHERE is_deleted = 0 AND attend_org_id = 521 AND attend_date BETWEEN '20240801' AND '20240831' AND attend_status & (2 | 4 | 8 | 16 | 8192) > 0;
最后一次出现时间:2024-09-09 13:10:41
5.0 分钟内总计执行 1 次,平均执行 3.906956 秒,平均锁 0.000097 秒,最大执行 3.906956 秒, 最大扫描 68853 行, 最大返回 1 行。
hhhhhccccc
64 天前
这种我用的 json, 索引上用的 multi-value index, 但是几百个的我还真没整过, 可以试下


属性就存 id, 有的话, 值为 1, 就把属性 id 放到 attrs 中,

create table demo (
id int unsigned primary key,
name varchar(255) not null,
attrs json, -- int[], id 从另外一张表来
created_at xx,
updated_at xx,
index idx_attrs ((cast(attrs as unsigned array)))
);


你的要求
1. 占用空间尽量小 [v]
2. 查询方便 [v]
同时是 1
select json_contains(json_array(1,2,3), json_array(1,2)); -> 1
select json_contains(json_array(1,2,3), json_array(1,2, 3)); -> 0
select id, name from demo where json_contain(demo, '[1,2,3]');


其中有一个是 1
select json_overlaps(json_array(1,2,3), json_array(1,2,4)); -> 1
select json_overlaps(json_array(1,2,3), json_array(4)); -> 0
select id, name from demo where json_overlaps(demo, '[1,2,3]');

只查一个的话, 可以用 member of


项目中已经用了, 非常爽
总共数据量几百万, 快上千万, 速度快, explain 就知道不是 ref, 是 range

使用 json 的话, 写 sql 有时候会麻烦很多, 并且要做好前置的校验, 当然用 json 真的爽
sngxx
63 天前
1. 不管什么类型你都当成 bitmap 处理,空间都一样啊,除非你会做压缩——去掉尾部的 0 ;
2. mysql 没有 getbit 功能,你得先查出列的所有内容再 getbit ,用 mysql 的内置方法比如 SUBSTRING 执行时也是要查出整体才处理的;
3. 可行,将 bitmap 分段,查询一个 bit 时只需要查出一个 bigint 再取 bit ;

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/1070947

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX