我有一个大约100米行的测试数据库表,它是通过多次克隆原始3k行生成的。假设此表描述了一些具有时间戳的事件。由于克隆现在我们每天有大约10万个事件,这远非真实案例。所以我想将日期列随机化并将记录分散几天。 这是我提出的程序:
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秒,因此假设线性复杂,在100米的桌子上应用约50小时。有没有办法加快速度?或者我的程序可能不正确?
答案 0 :(得分:1)
只是做:
set @datarange = 7;
update `events`
set starttime = NOW() - INTERVAL FLOOR(RAND()) * @datarange DAY;
数据库不擅长在lopp中获取和处理单行,就像我们习惯于在过程语言(迭代器,每个循环,数组等)中一样,它们是最好的,并且针对处理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 |
+----------+
我们创建了一个包含17,000行的表。现在我们称之为程序:
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%更快 - 这是一个巨大的差异!!!