V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
awesomePower
V2EX  ›  程序员

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

  •  
  •   awesomePower · 68 天前 · 2116 次点击
    这是一个创建于 68 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

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

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

    只用一个 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
        12
    ntedshen  
       67 天前
    bigint 我之前测试过四五个属性的情况,可行而且位运算的性能在我这里比 mariadb 的 set 还优秀一些。。。
    就是维护比较地狱。。。
    也没测过几百个会是什么情况。。。

    find_in_set 我现在会用来存一些标签但是性能确实太不好看了,最近正在切到 json 。。。
    sagaxu
        13
    sagaxu  
       67 天前
    存储用多个 BIGINT 可以,查但询很麻烦。如果检索条件是这些 bits ,用 mysql 不太适合,每次都扫全表 100 万行就不行了,这种要上搜索引擎。
    Donjote
        14
    Donjote  
       67 天前
    好像容易出现慢 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
        15
    hhhhhccccc  
       66 天前
    这种我用的 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
        16
    sngxx  
       66 天前
    1. 不管什么类型你都当成 bitmap 处理,空间都一样啊,除非你会做压缩——去掉尾部的 0 ;
    2. mysql 没有 getbit 功能,你得先查出列的所有内容再 getbit ,用 mysql 的内置方法比如 SUBSTRING 执行时也是要查出整体才处理的;
    3. 可行,将 bitmap 分段,查询一个 bit 时只需要查出一个 bigint 再取 bit ;
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5389 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 05:50 · PVG 13:50 · LAX 21:50 · JFK 00:50
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.