>我需要从纯文本文件插入数据,将每行分解为 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
启用键;