从ID号生成唯一的序列号

时间:2015-06-30 18:48:46

标签: mysql

我有一个可以递增增加id的数据库。我需要一个函数将该id转换为0到1000之间的唯一数字。(实际的最大值要大得多,但为了简单起见。)

1 => 3301, 
2 => 0234, 
3 => 7928,
4 => 9821

生成的数字不能重复。 它不能是增量的。 需要它在运行中生成(不创建一个统一数字表来读取)

我认为是哈希函数,但存在冲突的可能性。 随机数也可能有重复数。 我需要一个最小的完美哈希函数,但找不到简单的解决方案。

2 个答案:

答案 0 :(得分:1)

由于标准有点模糊(足以欺骗普通人),我不确定要采取哪条路线。以下是一些想法:

  1. 您可以使用Pearson hash。根据维基百科页面:

      

    给定一组小的特权输入(例如,编译器的保留字),可以调整置换表,以便这些输入产生不同的散列值,产生所谓的完美散列函数。

  2. 您可以使用复杂的一对一数学函数。这样做的缺点是,由于一对一的要求,很难制造一个没有严格增加或严格减少的产品。如果你做了类似(id ^ 2) + id * 2之类的事情,那么ids之间的间隔会发生变化,如果不知道原始ID,这个函数就不会立即明显。

  3. 你可以这样做:

    new_id = (old_id << 4) + arbitrary_4bit_hash(old_id);
    

    这将给出唯一的ID,并且不会立即明显前4位只是垃圾(特别是在读取十进制格式的数字时)。与最后一个选项一样,新ID的顺序与旧ID相同。我不知道这是不是一个问题。

  4. 您可以通过使查找数组中包含“随机”数字来对所有ID转换进行硬编码。

  5. 您可以使用某种哈希函数生成器,如gperf

      

    GNU gperf是一个完美的哈希函数生成器。对于给定的字符串列表,它以C或C ++代码的形式生成散列函数和散列表,用于根据输入字符串查找值。散列函数是完美的,这意味着散列表没有冲突,并且散列表查找只需要单个字符串比较。

  6. 您可以使用加密安全机制使用密钥加密ID。

  7. 希望其中一个适合你。

    <强>更新

    这是OP要求的轮换班次:

    function map($number)
    {
        // Shift the high bits down to the low end and the low bits
        // down to the high end
        // Also, mask out all but 10 bits. This allows unique mappings
        // from 0-1023 to 0-1023
        $high_bits = 0b0000001111111000 & $number;
        $new_low_bits = $high_bits >> 3;
        $low_bits =  0b0000000000000111 & $number;
        $new_high_bits = $low_bits << 7;
        // Recombine bits
        $new_number = $new_high_bits | $new_low_bits;
        return $new_number;
    }
    
    function demap($number)
    {
        // Shift the high bits down to the low end and the low bits
        // down to the high end
        $high_bits = 0b0000001110000000 & $number;
        $new_low_bits = $high_bits >> 7;
        $low_bits =  0b0000000001111111 & $number;
        $new_high_bits = $low_bits << 3;
        // Recombine bits
        $new_number = $new_high_bits | $new_low_bits;
        return $new_number;
    }
    

    这种方法有其优点和缺点。我能想到的主要缺点(除了安全方面)是对于较低的ID,连续数字将完全相同(乘法)间隔,直到数字开始环绕。也就是说

    map(1) * 2 == map(2)
    map(1) * 3 == map(3)
    

    当然,这种情况会发生,因为数字越小,所有高位都为0,因此map函数等效于仅移位。这就是为什么我建议将伪随机数据用于较低位而不是数字的较高位。它会使常规间隔不那么明显。为了帮助缓解这个问题,我编写的函数只移动前3位并旋转其余部分。通过这样做,对于大于7的所有ID,常规间隔将不太明显。

答案 1 :(得分:0)

似乎它不是必须数字? MD5-Hash怎么样?

从......

中选择md5(id + rand(10000))