我有一个看起来像这样的MySQL表:
创建结构的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;
它存储了唯一的id
,responseCode
和lastUpdate
。 responseCode
是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
将是一个日期,我决定不管响应代码如何,都需要刷新早于该日期的任何日期。此外,如果我没有收到200
或404
,无论最后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表?
答案 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();
}
}