0

我需要从纯文本文件中插入数据,将每行分解为 2 个部分,然后插入到数据库中。我就是这样做的,但是这个程序可以优化速度吗?

该文件有大约 27000 行条目
DB 结构 [唯一键 (ext,info)]

  • 分机 [varchar]
  • 信息 [varchar]

代码:

$string = file_get_contents('list.txt');  
$file_list=explode("\n",$string);  
$entry=0;  

$db = new mysqli('localhost', 'root', '', 'file_type');  
$sql = $db->prepare('INSERT INTO info (ext,info) VALUES(?, ?)');  

$j=count($file_list);  
for($i=0;$i<$j;$i++)  
{  
 $data=explode(' ',$file_list[$i],2);   
 $sql->bind_param('ss', $data[0], $data[1]);  
 $sql->execute();  
 $entry++;  
}   
$sql->close();  
echo $entry.' entry inserted !<hr>';
4

5 回答 5

2

如果您确定该文件包含唯一的 ext/info 对,您可以尝试禁用导入密钥:

ALTER TABLE `info` DISABLE KEYS;

导入后:

ALTER TABLE `info` ENABLE KEYS;

这样,唯一索引将为所有记录重建一次,而不是每次插入某些内容时。

为了进一步提高速度,您应该将此文件的格式更改为与 CSV 兼容并使用 mysql LOAD DATA以避免解析 php.ini 中的每一行。

于 2012-04-30T17:41:16.713 回答
2

当要插入多个项目时,您通常将所有数据放入 CSV 文件中,创建一个包含与 CSV 匹配的列的临时表,然后执行LOAD DATA [LOCAL] INFILE,然后将该数据移动到目标表中。但正如我所见,您不需要太多额外的处理,因此您甚至可以将输入文件视为 CSV,而不会遇到任何额外的麻烦。

$db->exec('CREATE TEMPORARY TABLE _tmp_info (ext VARCHAR(255), info VARCHAR(255))');
$db->exec("LOAD DATA LOCAL INFILE '{$filename}' INTO TABLE _tmp_info
           FIELDS TERMINATED BY ' '
           LINES TERMINATED BY '\n'"); // $filename = 'list.txt' in your case
$db->exec('INSERT INTO info (ext, info) SELECT t.ext, t.info FROM _tmp_info t');

之后您可以运行COUNT(*)临时表以显示那里有多少记录。

于 2012-04-30T17:44:25.870 回答
0

这是神奇的解决方案 [3 秒 vs 240 秒]

更改表info禁用键;

$db->autocommit(FALSE);
//insert
$db->commit();

更改表info启用键;

于 2012-04-30T18:31:44.493 回答
0

如果你可以使用像Talend这样的东西。这是一个 ETL 程序,简单且免费(有付费版本)。

于 2012-04-30T17:59:28.747 回答
0

如果您有一个要读取的大文件,我不会使用file_get_contents. 通过使用它,您可以强制解释器一次将全部内容存储在内存中,这有点浪费。

以下是摘自此处的片段:

$file_handle = fopen("myfile", "r");
while (!feof($file_handle)) {
   $line = fgets($file_handle);
   echo $line;
}
fclose($file_handle);

这是不同的,因为您在单个实例中及时将文件保存在内存中的是一行(不是文件的全部内容),在您的情况下,这可能会降低脚本的运行时内存占用. 在您的情况下,您可以使用相同的循环来执行您的 INSERT 操作。

于 2012-04-30T17:45:55.530 回答