【问题标题】:Randomize timestamp column in large MySQL table随机化大型 MySQL 表中的时间戳列
【发布时间】:2013-08-01 03:06:16
【问题描述】:

我有一个大约 100m 行的测试数据库表,它是通过多次克隆原始 3k 行生成的。假设这张表描述了一些具有时间戳的事件。由于克隆,现在我们每天有大约 1000 万个事件,这与真实案例相去甚远。所以我想随机化日期列并分散几天的记录。 这是我想出的程序:

DROP PROCEDURE IF EXISTS `randomizedates`;
DELIMITER //
CREATE PROCEDURE `randomizedates`(IN `daterange` INT)
BEGIN
  DECLARE id INT UNSIGNED;
  DECLARE buf TIMESTAMP;
  DECLARE done INT DEFAULT FALSE;
  DECLARE cur1 CURSOR FOR SELECT event_id FROM events;
  DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;

  OPEN cur1;
  the_loop: LOOP
    FETCH cur1 INTO id;
    IF done THEN
      LEAVE the_loop;
    END IF;
    SET buf = (SELECT NOW() - INTERVAL FLOOR(RAND() * daterange) DAY);
    UPDATE events SET starttime = buf WHERE event_id = id;
  END LOOP the_loop;
  CLOSE cur1;
END //
DELIMITER ;

在 3k 表上,它执行约 6 秒,因此假设线性复杂性,在 100m 表上应用需要约 50 小时。有没有办法加快速度?或者我的程序根本不正确?

【问题讨论】:

    标签: mysql performance large-data


    【解决方案1】:

    只要做:

    set @datarange = 7;
    update `events`
    set starttime = NOW() - INTERVAL FLOOR(RAND()) * @datarange DAY;
    

    数据库不擅长在 lopp 中获取和处理单行,就像我们过去在过程语言(迭代器、for each 循环、数组等)中所做的那样,它们最擅长处理 SQL,并针对处理 SQL 进行了优化,即本质上是一种声明性语言 - 与用于指定程序必须执行的步骤的过程性语言相比,您可以在不指定如何执行的情况下声明您想要获得的内容。

    记住 - 逐行 = 慢慢变慢。

    查看模拟您的表格并将您的过程与 UPDATE 进行比较的简单示例:

    drop table `events`;
    create table `events` as 
    select * from information_schema.tables
    where 1=0; 
    
    alter table `events` add column event_id int primary key auto_increment first;
    
    alter table `events` change column create_time starttime timestamp;
    
    insert into `events`
    select null, t.*
    from information_schema.tables t
    cross join (
      select 1 from information_schema.tables
      limit 100
    ) xx
    
    mysql> select count(*) from `events`;
    +----------+
    | count(*) |
    +----------+
    |    17200 |
    +----------+
    

    我们创建了一个包含 17000 行的表。现在我们调用这个过程:

    mysql> call `randomizedates`(7);
    Query OK, 0 rows affected (34.26 sec)
    

    和更新命令:

    mysql>     set @datarange = 7;
    Query OK, 0 rows affected (0.00 sec)
    
    mysql>     update `events`
        ->     set starttime = NOW() - INTERVAL FLOOR(RAND()) * @datarange DAY;
    Query OK, 17200 rows affected (0.23 sec)
    Rows matched: 17200  Changed: 17200  Warnings: 0
    

    如您所见 - 34 秒 / 0.23 秒 = 快 14782 % - 这是一个巨大的差异!!!

    【讨论】:

      猜你喜欢
      • 2018-10-14
      • 2017-04-26
      • 2012-12-21
      • 2014-12-31
      • 1970-01-01
      • 2015-04-20
      • 1970-01-01
      • 2011-09-14
      • 1970-01-01
      相关资源
      最近更新 更多