0

我有一个大约 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 小时。有没有办法加快速度?或者也许我的程序根本不正确?

4

1 回答 1

1

做就是了:

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

数据库不擅长在 lopp 中获取和处理单行,就像我们在过程语言(迭代器、for each 循环、数组等)中所做的那样,它们最擅长并针对处理 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 % 快 - 这是一个巨大的差异!

于 2013-07-31T21:15:19.873 回答