【问题标题】:Fastest way to generate 11,000,000 unique ids生成 11,000,000 个唯一 ID 的最快方法
【发布时间】:2013-12-05 07:52:57
【问题描述】:

我正在尝试创建按顺序生成 11,000,000 百万个唯一 ID 的 php 脚本。但是,我试图在 20 分钟内快速完成它应该生成这 1100 万个唯一 ID。此外,一旦它达到 12,000,000,它应该环绕并从零开始。

这是我目前所拥有的。该脚本一次只会返回一个 id。我刚刚添加了一个循环来查看生成 id 需要多长时间。

while(true){

    try {

        $this->getAdapter()->query('INSERT INTO generate_ids (assigned_id) SELECT (MAX(assigned_id)+1) FROM generate_ids');
        $id = $this->getAdapter()->lastInsertId();


        $sql = 'SELECT assigned_id FROM generate_ids WHERE id = $id';  
        $query = $this->getAdapter()->query($sql);
        $result = $query->fetchAll();
            //Live system would return id here
        $assigned_id = $result[0]['assigned_id'];


    } catch (Exception $e) {
        //do nothing
    }

    if($count == 11000000){
        die();
    }

    $count++;
}

}

【问题讨论】:

  • 一个好的第一步是不要一次做一行。
  • 为什么不直接使用AUTO_INCREMENT?还有为什么一定要选择刚才生成的ID呢?您不信任创建记录的数据库吗?
  • 是的,就像@siride 说的那样,一次执行 1 行会导致调用 11,000,000 个查询,这将非常慢……如果每个请求花费 200 毫秒,则运行需要 6,111 小时我相信这个脚本。
  • 完全不清楚您要完成什么。将生成的 id 值存储在表中是否重要?看不懂//Live system would return id here的评论,把id返回到什么进程,怎么返回?您是否需要填充具有 11,000,000 行的表?鉴于您在达到 12,000,000 时指定了一个换行,我们假设 id 也需要是连续的(不仅仅是唯一的)并且 id 的范围应该是 1,000,001 到 12,000,000(或 1,000,000 到 11,999,999)?
  • @Joshua Smock:如果每个 SQL 执行平均需要 200 毫秒,那将是大约 1,222 小时。 (每次循环执行两次 SQL(一个 INSERT 和一个 SELECT):22,000,000 次执行 * 200ms = 1,222 小时。

标签: php mysql scripting


【解决方案1】:

如果您需要一次插入所有 ID(出于某种原因),最快的方法是在纯 SQL 中完成

insert into generate_ids (assigned_id)
select N
from
(
select a.N + b.N * 10 + c.N * 100 + d.N * 1000 + e.N * 10000 + f.N * 100000 + g.N * 1000000 + h.N * 10000000 + 1 as N
from (select 0 as N union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) a
    ,(select 0 as N union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) b
    ,(select 0 as N union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) c
    ,(select 0 as N union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) d
    ,(select 0 as N union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) e
    ,(select 0 as N union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) f
    ,(select 0 as N union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) g
    ,(select 0 as N union all select 1) h
order by N
) q
 where N <= 11000000

在我的笔记本电脑上完成不到一分钟。

【讨论】:

    【解决方案2】:

    如果创建下表:

     CREATE TABLE sequence (
         sequence_id BIGINT NOT NULL AUTO_INCREMENT,
         PRIMARY KEY (`sequence_id`)
    ) 
    

    然后依次发出这三个查询:

    INSERT INTO sequence () VALUES ();
    DELETE FROM sequence WHERE sequence_id < LAST_INSERT_ID();
    SELECT LAST_INSERT_ID() AS sequence;
    

    第三个查询保证返回一个唯一的序列号。即使您有数十个不同的客户端程序连接到您的数据库,此保证仍然有效。这就是 AUTO_INCREMENT 的美妙之处。

    您可以在需要时使用这些 SQL 查询来获取唯一的序列号,而不是预先生成一千一百万个这些序列号。

    如果您必须在序列号 1200 万处回绕,则可以改用这些查询。

    INSERT INTO sequence () VALUES ();
    DELETE FROM sequence WHERE sequence_id < LAST_INSERT_ID();
    SELECT LAST_INSERT_ID() MOD 12000000 AS sequence;
    

    这里的诀窍是使用自动递增的序列号来保证唯一性,但还要删除表中的行,以免占用大量空间。

    请注意,您还可以将 LAST_INSERT_ID() 的序列号用于其他目的,例如。

    INSERT INTO sequence () VALUES ();
    DELETE FROM sequence WHERE sequence_id < LAST_INSERT_ID();
    INSERT INTO user (userid, username, phone) 
              VALUES (LAST_INSERT_ID() MOD 12000000, 'Joe', '800-555-1212');
    SELECT LAST_INSERT_ID() MOD 12000000 AS sequence;
    

    【讨论】:

      猜你喜欢
      • 2011-01-25
      • 1970-01-01
      • 2017-08-26
      • 2010-12-08
      • 1970-01-01
      • 2011-02-19
      • 1970-01-01
      • 2013-04-11
      • 2010-09-18
      相关资源
      最近更新 更多