使用PHP的大量SQLite插入

时间:2011-05-09 13:23:27

标签: php sqlite pdo

我有大约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。 有更好(更快)的方法吗?

4 个答案:

答案 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')”的问题,则每个查询都将整个文本字符串发送到数据库以进行重新解析解析。

加速它的另一件事 - 将整个循环包装在事务中,然后在循环结束时提交事务。