优化将 27000*2 个密钥从纯文本文件插入数据库的代码


optimizing Code for inserting 27000*2 keys from plain text file to DB

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

该文件有大约 27000 行条目
数据库结构 [唯一键 (分机,信息)]

  • 分机 [瓦尔查尔]
  • 信息 [瓦尔查尔]

法典:

$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>';

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

ALTER TABLE `info` DISABLE KEYS;

导入后:

ALTER TABLE `info` ENABLE KEYS;

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

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

当有多个项目要插入时,通常将所有数据放在 CSV 文件中,创建一个具有与 CSV 匹配的列的临时表,然后执行加载数据 [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(*)以显示有多少记录。

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

以下是从这里摘取的片段:

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

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

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

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

更改表info禁用键;

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

更改表info启用键;