V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
iseki
V2EX  ›  问与答

有人存身份证号时丢掉最后一位吗

  •  
  •   iseki · 83 天前 · 5404 次点击
    这是一个创建于 83 天前的主题,其中的信息可能已经有所发展或是发生改变。
    最后一位校验位去掉,剩下的部分按数字存 int64 理论上没问题,有人考虑这么干吗
    44 条回复    2022-09-13 10:57:47 +08:00
    oneisall8955
        1
    oneisall8955  
       83 天前 via Android
    读出来那还要算一下?查找时候呢
    imicksoft
        2
    imicksoft  
       83 天前
    按身份证算法,知道前面的,最后一位可以算出来
    IvanLi127
        3
    IvanLi127  
       83 天前 via Android
    数字的话,模糊匹配会不会很蛋疼。还有就是,怕领导哪天想着去掉校验,允许存错的可咋整
    wxf666
        4
    wxf666  
       83 天前   ❤️ 5
    其实 int64 可以完全存下,包括校检位在内的,完整身份证号:

    1. 用 ⌈ log2(10^17) ⌉ = 57 位来存前 17 位数字
    2. 用 ⌈ log2(11) ⌉ = 4 位来存校检位

    还剩 64 - 57 - 4 = 3 位空闲


    或者,校检位视为两位数(那么身份证就是 19 位),刚好可用 ⌈ log2(10^19) ⌉ = 64 位存下
    eason1874
        5
    eason1874  
       83 天前   ❤️ 2
    别整花里胡哨的,CPU 比硬盘内存贵多了,用空间换时间是最有性价比的
    janus77
        6
    janus77  
       83 天前
    可以但没必要
    少一位数字能省多少磁盘啊
    Kinnice
        7
    Kinnice  
       83 天前 via Android
    有没有可能用户输得是错的
    iseki
        8
    iseki  
    OP
       83 天前 via Android
    @oneisall8955 @IvanLi127 如果是字符串正则查找,那确实是不行了,不过我没见过这种场景;允许存错误的身份证号这就没办法了🤣除非在一开始明确提出我不会考虑这种需求

    @wxf666 可以是可以,主要会不直观,如果只是简单去掉最后一位,不影响以十进制方式阅读

    @janus77 主要是便于用数值而非字符串类型存储,19+字节变成定长 8 字节吧,我觉得对于某些量大的场景还是很划算的。

    @eason1874 只有在系统边界将身份证号类型装换成字符串类型传输的时候才需要计算和补足最后一个校验码,校验算法非常简单,所以应该不会消耗过多的 CPU
    iseki
        9
    iseki  
    OP
       83 天前 via Android
    话说大家真的有遇到过身份证号模糊匹配的需求吗,这点有些好奇,我确实没见过…
    wxf666
        10
    wxf666  
       83 天前   ❤️ 1
    @iseki

    > 可以是可以,主要会不直观,如果只是简单去掉最后一位,不影响以十进制方式阅读

    那『校检位视为两位数(那么身份证就是 19 位)』适合你啊。比如:

    - 123456789012345678 会存储为:1234567890123456708
    - 12345678901234567X 会存储为:1234567890123456710
    iseki
        11
    iseki  
    OP
       83 天前 via Android
    @wxf666 视为两位十进制数这点我没想到,我光考虑前面那种了🤣
    iseki
        12
    iseki  
    OP
       83 天前 via Android
    @wxf666 还是不行,很多地方不便于使用 无符号数,那么实际上可用的值最大只有 2^63 ,溢出了
    GuuJiang
        13
    GuuJiang  
       83 天前
    强烈反对这样做,并不是所有看起来由 0-9 组成的东西都是数字,身份证号、银行卡号、学号等本质是“数码”而不是“数字”,对这类“数字”进行数学运算是没有任何意义的,可能存在的运算是作为字符串运算(因为现实当中制定数码时通常会让某一段具备某种含义),讽刺的是,哪怕微软都在犯这种低级错误
    wxf666
        14
    wxf666  
       83 天前   ❤️ 1
    @iseki 那就正负号代表校检位是否不为 X 呗。。比如:

    - 123456789012345678 会存储为:123456789012345678
    - 12345678901234567X 会存储为:-123456789012345670

    需要使用 1 位符号位 + ⌈ log2(10^18) ⌉ = 1 + 60 = 61 位
    iseki
        15
    iseki  
    OP
       83 天前 via Android   ❤️ 1
    @GuuJiang 换一个思考方式会不会好一点:我只是借用了一个 64bit 的数据类型(这个类型很常见)并没有把它当作数值进行计算,实际上这也没有意义;
    而所谓的字符串也好,我这种做法也好,实际上都是身份证号的一种编码方式,相对于 144bit 更加节省而已~
    janus77
        16
    janus77  
       83 天前
    @iseki #8 没那么多吧……按你这样算,就算我每个身份证号可以减少 10 个字节,15 亿个也就减少十几个 G ,不知道算对了没?
    iseki
        17
    iseki  
    OP
       83 天前
    当然,程序内部往往不存在借用类型的需要,这种情况应该创建一个正常的「身份证号」数据类型,我所谓的「借用」更多时候指在 SQL 数据库中,有些数据库不能方便的创建类型别名或者增加自定义类型
    iseki
        18
    iseki  
    OP
       83 天前
    @janus77 的是,其实一共也没多少
    iseki
        19
    iseki  
    OP
       83 天前
    得···打错了···的是 -> 是的
    dcsuibian
        20
    dcsuibian  
       83 天前 via Android
    身份证号存数字。。。来个模糊搜索看看
    agagega
        21
    agagega  
       83 天前 via iPhone
    身份证号分段存 int 里,不到 50 位也能解决。所以就算存校验位你也可以单独拿出来。
    ClarkAbe
        22
    ClarkAbe  
       83 天前 via Android
    你们身份证存明文?不过等保不怕泄漏嘛
    wxf666
        23
    wxf666  
       83 天前
    @IvanLi127 @dcsuibian 一般身份证的模糊搜索,都是些啥需求呢?

    - 查找所有 x 省 y 市 z 区 /县 的人?
    - 查找所有 35 岁以上的人?
    - 查找所有 x 省 y 市 z 区 /县 20 岁 ~ 35 岁 的人?
    wxf666
        24
    wxf666  
       83 天前
    @agagega 分段存。。咋存能 < 50 位?

    是想办法去除不可能存在的数字吗?

    比如用 16 位来存出生年月日(足够 180 年)?
    dcsuibian
        25
    dcsuibian  
       83 天前
    @wxf666 对啊,就这种用字符串做的话就很方便啊。
    更一般点,最最普通的模糊搜索,就是写身份证片段,然后列出所有相关的吧。字符串 like 一下就很简单,但换成数字就很难做的。
    jim9606
        26
    jim9606  
       83 天前 via Android
    不是为了极限缩减数据库存储的没必要这么搞。
    要知道存证件号的字段有可能扩展为存任意证件号,难道你们会为每一种证件类型开一列?
    wxf666
        27
    wxf666  
       83 天前
    @dcsuibian 假设用『校检位视为两位数(那么身份证就是 19 位)』方法:

    (`SQL` 大意,具体写要改成 `DIV`、`CAST(1e13 AS UNSIGNED)` 等)


    1. 查找所有 x 省 y 市 z 区 /县 的人

    - 不用索引:`身份证号 / 1e13 = 123456`

    - 要用索引:`身份证号 BETWEEN 1234560000000000000 AND 1234569999999999999`


    2. 查找所有 35 岁以上的人

    - 不用索引:`身份证号 / 1e5 % 1e8 < 19870912`


    3. 查找所有 x 省 y 市 z 区 /县 20 岁 ~ 35 岁 的人

    - 要用索引:`身份证号 BETWEEN 1234561987091200000 AND 1234562002091299999`
    agagega
        28
    agagega  
       83 天前 via iPhone
    @wxf666
    前六位所在地用 20 位整数可以表示(如果熟悉相关国家标准还可以进一步压缩)
    出生年存 8 位整数,表示 1900 年以来的年数
    出生月存 4 位整数
    出生日存 5 位整数
    最后 3 位存 10 位整数

    虽然这样挺无聊的…
    xxfye
        29
    xxfye  
       83 天前
    你们这些人好勇啊。
    用大量身份证进行遍历,准不准另说,合规就是大问题吧。
    wxf666
        30
    wxf666  
       83 天前
    @dcsuibian

    修改一下:

    `身份证号 / 1e5 % 1e8 < 19870912` 应该可以改成 `身份证号 % 1e13 < 1987091200000`


    > 写身份证片段,然后列出所有相关的

    这个需求,是不是要一直扫表了。。

    实在不行,就实时转换成原身份证号再 LIKE 呗:

    CONCAT(身份证号 DIV 100, MID('0123456789X', 身份证号 % 100 + 1, 1)) LIKE ...
    wxf666
        31
    wxf666  
       83 天前
    @agagega 那想得差不多一样,针对各个部分(行政区划代码、出生年月日、顺序码)进行各自编码,减少不必要的编码位浪费

    也确实如你所说,意义不大。。
    iyaozhen
        32
    iyaozhen  
       83 天前
    @ClarkAbe 还是这位老哥说到对。信息安全任重道远呀。

    之前喜欢扣位数,但现在 varchar 用的多,因为越来越多的需要加密存储了,或者一开始能得到的就不是完整的
    iseki
        33
    iseki  
    OP
       83 天前 via Android
    @jim9606 要是我一定会单开字段,或者弄成一个 json 字段
    cxk0
        34
    cxk0  
       83 天前   ❤️ 1
    你就是想身份证存数字.那就把最后一位 X 的话,去掉一位,其他照常存,这样遇到 X 结尾的数据自然会比其他数据小一位。


    非 X 直接数字可存。
    mythabc
        35
    mythabc  
       83 天前
    那护照另开一个表存吗?
    奇葩的还有一堆证件号是带括号的,即使是英文字符,用户也会给你输一堆奇奇怪怪的东西进来。
    dcsuibian
        36
    dcsuibian  
       83 天前
    @wxf666 这么做是可以,但无论是对 DBA 和程序员来说都并不友好,增加了操作和代码的复杂度,同时在检索时还会增加数据库的计算量。

    用数字存储减少磁盘占用。int64 算 8 字节,14 亿个是 10.43GB ,我这里 sizeof(身份证字符串)是 19 字节,直接算 3 倍好了。那也就是 31.2GB 。现在这个时代,省这点容量是真的划不来。

    至于模糊查询,我觉得在公司、企业、学校 OA 系统中比较有可能出现。主要是这种查询多变没法提前写好。
    kingjpa
        37
    kingjpa  
       83 天前
    都没做过业务层的 curd 吗?

    除了金融类 哪个业务输入 18 位身份证号?

    不都是后 6 位?
    wellerman
        38
    wellerman  
       83 天前
    我在业务上遇到过。分 3 段存,X 直接替换成 10 。比较完美。
    panerai
        39
    panerai  
       83 天前
    话说你们身份证存的时候不脱敏的吗?
    dlsflh
        40
    dlsflh  
       82 天前 via Android
    我想知道要是有人存了一位伟人的身份证号这时候会怎么处理?
    makun123
        41
    makun123  
       82 天前
    我想知道 你们数据库存的身份证号难道是明文存储么?
    Yuunie
        42
    Yuunie  
       82 天前
    ```javascript
    function idCardLast(id = '') {
    if (id.length !== 17) return false
    const rules = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]
    const lastSymbol = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2']
    const lastIndex = (Array.from(id).reduce((sum, value, index) => {
    return sum + (value * rules[index])
    }, 0)) % 11
    return lastSymbol[lastIndex]
    }
    ```
    paouke
        43
    paouke  
       82 天前
    我也想问,直接就身份证号明文存库,这么勇的吗
    stoluoyu
        44
    stoluoyu  
       82 天前
    虽然但是,身份证号要加密存。
    关于   ·   帮助文档   ·   API   ·   FAQ   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   1068 人在线   最高记录 5497   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 401ms · UTC 21:01 · PVG 05:01 · LAX 13:01 · JFK 16:01
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.