如何为表的主键创建唯一的随机整数ID?

发布于 2024-10-03 00:43:01 字数 59 浏览 7 评论 0原文

我想知道是否有人知道为表的主键创建唯一的随机整数 id 的好方法。我正在使用MySQL。该值必须是整数。

I was wondering if anybody knew a good way to create a unique random integer id for a primary key for a table. I'm using MySQL. The value has to be integer.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

绿光 2024-10-10 00:43:01

回应: “因为我想使用该值编码为 Base62,然后将其用于 url 中的 id。如果我自动递增,用户可能会很明显如何url id 已生成。”

如果安全是您的目标,那么使用 Base62,即使使用“随机”生成的数字也无济于事。

更好的选择是:

  • 不要重新发明轮子——使用 AUTO_INCRMENT
  • 然后使用加密哈希函数 + 随机生成的字符串(隐藏在该特定 url 的数据库中)来生成最终的“唯一”该 url 的 id"

In response to: "Because I want to use that value to Encode to Base62 and then use that for an id in a url. If i auto increment, it might be obvious to the user how the url id is generated."

If security is your aim then using Base62, even with a "randomly" generated number won't help.

A better option would:

  • Do not re-invent the wheel -- use AUTO_INCREMENT
  • Then use a cryptographic hash function + a randomly generated string (hidden in the db for that particular url) to generate the final "unique id for that url"
开始看清了 2024-10-10 00:43:01

如果您愿意接受建议并且可以实现它,请使用 UUID。
MySQL 的 UUID() 函数将返回一个 36 个字符的值,可用于 ID

如果您想使用整数,我仍然认为您需要创建一个将在 INSERT 语句中使用的函数 getRandID() 。该函数需要使用随机 + 检查现有 id 来返回之前未使用过的 id。

检查 MySQL 的 RAND() 函数。

If your're open to suggestions and you can implement it, use UUIDs.
MySQL's UUID() function will return a 36 chars value which can be used for ID.

If you want to use integer, still, I think you need to create a function getRandID() that you will use in the INSERT statement. This function needs to use random + check of existing ids to return one that is not used before.

Check RAND() function for MySQL.

故乡的云 2024-10-10 00:43:01

如何生成 unique_ids 是一个有用的问题 - 但您似乎对何时生成它们做出了适得其反的假设!

我的观点是,您不需要在创建行时生成这些唯一的 id,因为它们本质上独立于插入的数据。

我所做的是预先生成唯一的 id 以供将来使用,这样我就可以享受自己的甜蜜时光并绝对保证它们是唯一的,并且在插入时无需进行任何处理。

例如,我有一个订单表,其中包含 order_id。当用户输入订单时,此 id 会动态生成,递增 1、2、3 等,直到永远。用户不需要看到这个内部ID。

然后我有另一个表 - unique_ids 与(order_id,unique_id)。我有一个每天晚上运行的例程,它会在该表中预加载足够的 unique_id 行,以覆盖未来 24 小时内可能插入的订单。 (如果我有一天收到 10000 个订单,我就会遇到问题 - 但这将是一个好问题!)

这种方法保证了唯一性,并将任何处理负载从插入事务转移到批处理例程中,其中不影响用户。

How you generate the unique_ids is a useful question - but you seem to be making a counter productive assumption about when you generate them!

My point is that you do not need to generate these unique id's at the time of creating your rows, because they are essentially independent of the data being inserted.

What I do is pre-generate unique id's for future use, that way I can take my own sweet time and absolutely guarantee they are unique, and there's no processing to be done at the time of the insert.

For example I have an orders table with order_id in it. This id is generated on the fly when the user enters the order, incrementally 1,2,3 etc forever. The user does not need to see this internal id.

Then I have another table - unique_ids with (order_id, unique_id). I have a routine that runs every night which pre-loads this table with enough unique_id rows to more than cover the orders that might be inserted in the next 24 hours. (If I ever get 10000 orders in one day I'll have a problem - but that would be a good problem to have!)

This approach guarantees uniqueness and takes any processing load away from the insert transaction and into the batch routine, where it does not affect the user.

递刀给你 2024-10-10 00:43:01

您可以为表使用 AUTO_INCRMENT,但为用户提供加密版本:

encrypted_id: SELECT HEX(AES_ENCRYPT(id, 'my-private-key'));

id:选择 AES_DECRYPT(UNHEX(encrypted_id), '我的私钥');

You can use an AUTO_INCREMENT for your table, but give the users the encrypted version:

encrypted_id: SELECT HEX(AES_ENCRYPT(id, 'my-private-key'));

id: SELECT AES_DECRYPT(UNHEX(encrypted_id), 'my-private-key');

一紙繁鸢 2024-10-10 00:43:01

这种方法怎么样(PHPMySQL):


  1. user_id(唯一)生成随机数字
  2. 插入行,生成的numberuser_id
  3. 如果插入的行数等于0,则转到第1 点

看起来很重?继续阅读。


Long

表:

users (user_id int UNIQUE)

代码:

<?php
// values stored in configuration
$min = 1;
$max = 1000000;

$numberOfLoops = 0;
do {
    $randomNumber = rand($min, $max);

    // the very insert
    $insertedRows = insert_to_table(
        'INSERT INTO foo_table (user_id) VALUES (:number)', 
        array(
            ':number' => $randomNumber
        ));

    $numberOfLoops++;

    // the magic
    if (!isset($reported) && $numberOfLoops / 10 > 0.5) {
        /**
         * We can assume that at least 50% of numbers
         * are already in use, so increment values of
         * $min and $max in configuration.
         */
        report_this_fact();
        $reported = true;
} while ($insertedRows < 1);

  1. 所有值($min$max0.5)仅用于解释和它们没有统计意义。
  2. 函数 insert_to_tablereport_this_fact 不是用 PHP 构建的。这些也只是为了澄清解释目的而采用数字。

How about this approach (PHP and MySQL):


Short

  1. Generate random number for user_id (UNIQUE)
  2. Insert row with generated number as user_id
  3. If inserted row count equal to 0, go to point 1

Looks heavy? Continue to read.


Long:

Table:

users (user_id int UNIQUE)

Code:

<?php
// values stored in configuration
$min = 1;
$max = 1000000;

$numberOfLoops = 0;
do {
    $randomNumber = rand($min, $max);

    // the very insert
    $insertedRows = insert_to_table(
        'INSERT INTO foo_table (user_id) VALUES (:number)', 
        array(
            ':number' => $randomNumber
        ));

    $numberOfLoops++;

    // the magic
    if (!isset($reported) && $numberOfLoops / 10 > 0.5) {
        /**
         * We can assume that at least 50% of numbers
         * are already in use, so increment values of
         * $min and $max in configuration.
         */
        report_this_fact();
        $reported = true;
} while ($insertedRows < 1);

  1. All values ($min, $max, 0.5) are just for explanation and they have no statistical meaning.
  2. Functions insert_to_table and report_this_fact are not build in PHP. The are also as numbers just for clarify of explanation purposes.
热血少△年 2024-10-10 00:43:01

我的方式,适用于 32 位和 64 位平台。结果是64位

function hexstr2decstr($hexstr){
    $bigint = gmp_init($hexstr, 16);
    $bigint_string = gmp_strval($bigint);
    return $bigint_string;
}

function generate_64bitid(){
    return substr(md5(uniqid(rand(), true)), 16, 16);
}

function dbGetUniqueXXXId(){
    for($i = 0; $i < 10; $i++){
        $decstr = hexstr2decstr(generate_64bitid());

        //check duplicate for mysql.tablexxx
        if($dup == false){
            return $decstr;
        }
    }
    return false;
}

my way, for both 32bit and 64bit platform. result is 64bit

function hexstr2decstr($hexstr){
    $bigint = gmp_init($hexstr, 16);
    $bigint_string = gmp_strval($bigint);
    return $bigint_string;
}

function generate_64bitid(){
    return substr(md5(uniqid(rand(), true)), 16, 16);
}

function dbGetUniqueXXXId(){
    for($i = 0; $i < 10; $i++){
        $decstr = hexstr2decstr(generate_64bitid());

        //check duplicate for mysql.tablexxx
        if($dup == false){
            return $decstr;
        }
    }
    return false;
}
痕至 2024-10-10 00:43:01

AUTO_INCRMENT 将是您最好的选择。

这里是一些示例。

如果需要,您可以调整增量值的起始位置(默认为 1)。

AUTO_INCREMENT is going to be your best bet for this.

Here are some examples.

If you need to you can adjust where the increment value starts (by default it's 1).

毁我热情 2024-10-10 00:43:01

有一个AUTO_INCRMENT功能。我会用那个。

请参阅此处更多示例。

There is an AUTO_INCREMENT feature. I would use that.

See here more examples.

孤寂小茶 2024-10-10 00:43:01

是的,您可以,如果您不想,请不要使用 AUTO_INCRMENT。

试试这个:

CREATE TABLE `demotable` (
    `MyKey` BIGINT(20) NOT NULL DEFAULT floor(rand() * 1000000),'utf8_general_ci',
    `MyValue` BIGINT(20) NULL DEFAULT NULL,
    PRIMARY KEY (`MyUUID`)
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB
;

它创建一个主键 MyKey ,它的默认值是一个随机整数表达式。

看看你自己,当你添加像他这样的值时,它会创建一个新的随机密钥:

INSERT INTO demotable(MyValue) VALUES(1)

Yes you can, don't use AUTO_INCREMENT if you don't want to.

Try this:

CREATE TABLE `demotable` (
    `MyKey` BIGINT(20) NOT NULL DEFAULT floor(rand() * 1000000),'utf8_general_ci',
    `MyValue` BIGINT(20) NULL DEFAULT NULL,
    PRIMARY KEY (`MyUUID`)
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB
;

It creates a primary key MyKey and the default value for it is an expression that is a random integer.

See yourself, it creates a new random key when you add a value like his:

INSERT INTO demotable(MyValue) VALUES(1)
贱人配狗天长地久 2024-10-10 00:43:01

正如其他人也提到的,UUID 是一个满足您期望的强大工具。

但是你可以做一个小的修改,这样你就不必每次都自己分配(与“AUTOINCRMENT”的方式相同):

CREATE TABLE users (
  id VARCHAR(36) PRIMARY KEY DEFAULT UUID()
)

但它仍然有一个缺点:它占用大量存储空间。如果你的数据库很小那么就可以了,否则,你可以考虑使用mysql的内置函数(mysql 8.0+)将其转换为二进制。它占用的存储空间较少。

CREATE TABLE users (
  id BINARY(16) PRIMARY KEY DEFAULT UUID_TO_BIN(UUID())
)

并以这种方式阅读:

SELECT 
  BIN_TO_UUID(id) id 
FROM users

As others also mentioned, UUID is a powerful tool for what you expect.

But you can do a small modification so that you won't have to assign it yourself every time (the same way as "AUTOINCREMENT"):

CREATE TABLE users (
  id VARCHAR(36) PRIMARY KEY DEFAULT UUID()
)

But it still has a downside: It occupies a lot of storage. If your database is small then it is ok, otherwise, you can consider converting it to binary using mysql's built-in functions (mysql 8.0+). It occupies less storage.

CREATE TABLE users (
  id BINARY(16) PRIMARY KEY DEFAULT UUID_TO_BIN(UUID())
)

And read from it this way:

SELECT 
  BIN_TO_UUID(id) id 
FROM users
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文