【问题标题】:Large number of SQLite inserts using PHP使用 PHP 的大量 SQLite 插入
【发布时间】:2011-05-09 13:23:26
【问题描述】:

我尝试使用 PHP PDO 将大约 14000 行逗号分隔值插入到 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。 有没有更好(更快)的方法来做到这一点?

【问题讨论】:

    标签: php sqlite pdo


    【解决方案1】:

    如果您想要更快的速度,请使用准备/提取,这样 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')”之类的东西,就会出现问题,每个查询都会将整个文本字符串发送到数据库以重新已解析。

    还有一件事可以加快速度——将整个循环包装在一个事务中,然后在循环完成时提交该事务。

    【讨论】:

    • 是否有一些条件可以让它工作? stackoverflow.com/questions/34878681/… 似乎还没有结束
    • 嗯,是的,它很快,但它不会做你想要的。您需要在循环中进行绑定,您的代码只会一遍又一遍地插入相同的值。
    【解决方案2】:

    通过将插入包装在单个事务中,您将看到良好的性能提升。如果您不这样做,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();
    
    ?>
    

    【讨论】:

    • 这对我来说效果很好。我对它导入所有内容的速度感到惊讶。谢谢。
    • 谢谢您,您为我节省了很多时间! :)
    • 为了获得更快的速度,将语句准备与事务结合使用。如果值可能会影响实际查询,例如有意外的引号,也会使事情变得更安全。
    【解决方案3】:

    在循环之前启动事务并在循环之后提交它
    你的代码现在的工作方式,它在每​​次插入时都会启动一个事务

    【讨论】:

      【解决方案4】:

      来自SQLlite FAQ

      交易速度受磁盘驱动器速度的限制,因为(默认情况下) SQLite 实际上是等到数据 确实安全地存储在磁盘上 交易前浮出水面 完全的。那样的话,如果你突然 断电或如果您的操作系统崩溃,您的 数据仍然是安全的。有关详细信息,请阅读 关于 SQLite 中的原子提交.. [...]

      另一个选项是运行 PRAGMA synchronous=OFF。该命令将 导致 SQLite 不等待数据 到达磁盘表面,这将 使写操作看起来是 快多了。但如果你在 在交易中间,您的 数据库文件可能会损坏。

      我想说最后一段是你需要的。

      编辑:对此不确定,但我相信使用 sqlite_unbuffered_query() 应该可以解决问题。

      【讨论】:

        猜你喜欢
        • 2013-08-15
        • 1970-01-01
        • 1970-01-01
        • 2021-12-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多