使用大量行快速填充MySQL

时间:2012-10-08 19:50:32

标签: mysql

我有一个看起来像这样的MySQL表:

MySQL Table: status

创建结构的SQL是:

CREATE TABLE `status` (
`id` INT(11) NOT NULL,
`responseCode` INT(3) NOT NULL DEFAULT '503',
`lastUpdate` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

它存储了唯一的idresponseCodelastUpdateresponseCode是HTTP请求响应代码:404,500,503,200等

我有一个与我发出HTTP请求的每个id对应的URL,并在此表中记录我发出请求和收到响应的时间。

该脚本针对status表进行此查询:

SELECT id FROM status WHERE lastUpdate < 'XXXX' OR 
(responseCode != 200 AND responseCode != 404) 
ORDER BY id DESC LIMIT 100

XXXX将是一个日期,我决定不管响应代码如何,都需要刷新早于该日期的任何日期。此外,如果我没有收到200404,无论最后lastUpdate日期如何,我都想重新尝试HTTP请求。我LIMIT到100,因为我一次只运行100,然后我让它睡了一会儿再做100次,依此类推。

无论如何,一切都很好,但我想要做的就是提前填写表格,如下所示:

(1, 503, NOW()), (2, 503, NOW()), (3, 503, NOW()) ... (100000, 503, NOW())

注意,只有ID正在递增,但根据我的需要,它可能不一定从1开始。我希望这样的表预先填充,因为那样上面的查询可以继续抓取id用于我们需要重新尝试的那些,并且我不想再在{{1因为status是有限的并且不会改变(但是它们中有很多)。

我尝试过使用JAVA,(虽然PHP,C#或其他任何相同的概念,对我来说无关紧要):

id

这会启动插入,但问题是填充表需要花费大量时间(我没有确切的时间,但它运行了几个小时)。所以,我的问题归结为:是否有一种简单有效的方法来填充像这样大量行的MySQL表?

4 个答案:

答案 0 :(得分:12)

一般来说,您可以使用以下任何一项或多项:

  • 启动事务,执行插入,提交
  • 将多个值打包到查询中的单个插入
  • 在插入之前删除所有约束并在批量插入之后恢复约束(除了可能的主键,但不是很确定)但
  • 如果合适,请使用insert into ... select

第一个(使用事务)最有可能帮助,但我不确定它是否适用于myisam表,使用innodb它做得非常好 - 我只使用那些当我被迫使用mysql时,我更喜欢postgresql。

在您的特定情况下,插入100000行数据,您可以执行以下操作:

INSERT INTO status(id, responseCode, lastUpdate) SELECT @row := @row + 1 as row, 503, NOW() FROM 
(select 0 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) t,
(select 0 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) t2, 
(select 0 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) t3, 
(select 0 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) t4, 
(select 0 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) t5, 
(SELECT @row:=0) t6;

在我的机器上测试过,得到了:

Query OK, 100000 rows affected (0.70 sec)
Records: 100000  Duplicates: 0  Warnings: 0

我很确定你不能比100000行快得多。

答案 1 :(得分:9)

如何在主键上设置AUTO_INCREMENT

然后以您喜欢的方式插入前一百(或千)行(您的示例或DocJones给您的示例)。

然后使用

INSERT INTO table SELECT NULL, '503', NOW() FROM table;

......反复几次。这应该使表每次都加倍。

NULL第一个广告位中的SELECT可确保AUTO_INCREMENT启动并增加id

如果你想在桌子上种植甚至是faser,你可以做到

INSERT INTO table SELECT NULL, '503', NOW() FROM table AS t1 CROSS JOIN table t2;

...重复几次,这会使表格的大小增加,其功能为前两个尺寸+之前的尺寸(100 ^ 2 + 100)。

这也允许您自定义插入的值,例如,如果您想创建“随机”responseCodes,您可以使用类似CONCAT(ROUND(1+RAND()*4), '0', ROUND(RAND()*5))的内容,它将为您提供100到505之间的响应代码。 / p>

答案 2 :(得分:2)

PHP解决方案,批量加载100:

for ($i = 0; $i < 100000; $i+=100) {
  $vals = implode(', ', 
                  array_map(function($j) { return "($j, default, default)";},
                            range($i, $i+100)));
  mysqli_query($dbh, 'insert into status values ' . $vals) or die mysqli_error($dbh);
}

答案 3 :(得分:1)

您正在创建一个要执行的LARGE批处理语句。尝试使用例如在较小的包中拆分它。在循环内每1000次i(使用mod(i)yaddayadda)调用executeBatch()。这应该加快这个过程:

for( int i = 1; i <= 100000; i++ ) {
    st.setInt(1,i);
    st.addBatch();
    if (mod(i,1000)=0) {
       st.executeBatch();
    }
}
相关问题