我有大约14000行逗号分隔值,我试图使用PHP PDO插入到sqlite表中,如下所示:
<?php
// create a PDO object
$dbh = new PDO('sqlite:mydb.sdb');
$lines = file('/csv/file.txt'); // import lines as array
foreach ($lines as $line) {
$line_array = (','$line); // create an array of comma-separated values in each line
$values = '';
foreach ($line_array as $l) {
$values .= "'$l', ";
}
substr($values,-2,0); // get rid of the last comma and whitespace
$query = "insert into sqlite_table values ($values)"; // plug the value into a query statement
$dbh->query($query); // run the query
}
?>
这个查询需要很长时间,并且在没有中断的情况下运行它,我将不得不使用PHP-CLI。 有更好(更快)的方法吗?
答案 0 :(得分:19)
通过将插入包装在单个事务中,您将看到良好的性能提升。如果不这样做,SQLite会将每个插入视为自己的事务。
<?php
// create a PDO object
$dbh = new PDO('sqlite:mydb.sdb');
// Start transaction
$dbh->beginTransaction();
$lines = file('/csv/file.txt'); // import lines as array
foreach ($lines as $line) {
$line_array = (','$line); // create an array of comma-separated values in each line
$values = '';
foreach ($line_array as $l) {
$values .= "'$l', ";
}
substr($values,-2,0); // get rid of the last comma and whitespace
$query = "insert into sqlite_table values ($values)"; // plug the value into a query statement
$dbh->query($query); // run the query
}
// commit transaction
$dbh->commit();
?>
答案 1 :(得分:2)
在循环之前启动事务并在循环之后提交它 您的代码现在的工作方式,它在每个插入
上启动一个事务答案 2 :(得分:1)
来自SQLlite FAQ:
交易速度受磁盘驱动器速度限制,因为(默认情况下) SQLite实际上一直等到数据 确实安全地存储在磁盘上 交易前的表面 完成。那样,如果你突然 失去力量或者你的操作系统崩溃,你的 数据仍然安全。有关详情,请阅读 关于SQLite中的原子提交.. [...]
另一种选择是运行PRAGMA synchronous = OFF。这个命令会 导致SQLite不等待数据 到达磁盘表面,这将 使写操作看起来像 快多了。但如果你失去了力量 在交易的中间,你的 数据库文件可能已损坏。
我会说最后一段是你需要的。
编辑:对此不确定,但我相信使用sqlite_unbuffered_query()可以解决这个问题。
答案 3 :(得分:1)
如果您正在寻找更高的速度,请使用prepare / fetch,因此SQL引擎不必每次都解析出文本字符串。
$name = $age = '';
$insert_stmt = $db->prepare("insert into table (name, age) values (:name, :age)");
$insert_stmt->bindValue(':name', $name);
$insert_stmt->bindValue(':age', $age);
// do your loop here, like fgetcsv
while (get the data) {
list($name, $age) = split(',', $string);
$insert_stmt->execute();
}
在循环外进行绑定是违反直觉的,但这就是为什么这个方法如此之快,你基本上说“使用这些变量中的数据执行这个预编译查询”的原因之一。所以它甚至不需要在内部移动数据。并且您希望避免重新解析查询,如果您使用类似“插入表(名称)值('$ name')”的问题,则每个查询都将整个文本字符串发送到数据库以进行重新解析解析。
加速它的另一件事 - 将整个循环包装在事务中,然后在循环结束时提交事务。