简体   繁体   English

使用PDO向MySQL插入1000行的有效方法

[英]Efficient way to insert 1000 rows to MySQL with PDO

I have to insert 1000 rows of data per time into MySQL. 我必须每次将1000行数据插入MySQL。 At the moment, I use PDO and for-loop to insert row by row to database. 目前,我使用PDO和for循环逐行插入数据库。 Is there any more efficient way to achieve better performance? 有没有更有效的方法来实现更好的性能? Because I have to set max_execution_time to 5 minutes. 因为我必须将max_execution_time设置为5分钟。

function save()
{
            return $query = $this->insert("
                INSERT INTO gadata (landing_page, page_title, page_views, visits, visitors, bounce_rate, pageviews_per_visit, time_on_page, avg_time_on_page, day, month, year, hour)
                VALUES (:landing_page, :page_title, :page_views, :visits, :visitors, :bounce_rate, :pageviews_per_visit, :time_on_page, :avg_time_on_page, :day, :month, :year, :hour)", $this->data);
}

And

protected function insert($sql, array $data) {
    $q = $this->_db_handler->prepare($sql);

    foreach ($data as $k => $v)
    {
       $q->bindValue(':' . $k, $v);
    }

    $q->execute();
}

It is not PDO nor the way you are inserting makes insert so delayed, but innodb engine. 它不是PDO,也不是您插入的方式如此延迟插入,而是innodb引擎。 So you have 3 choices: 因此,您有3个选择:

  1. Wrap all inserts into transaction. 将所有插入内容包装到事务中。
  2. using root privileges, set innodb_flush_log_at_trx_commit variable to 2, to make innodb use a filecache for writes - it will make your inserts blazingly fast. 使用root特权,将innodb_flush_log_at_trx_commit变量设置为2,以使innodb使用文件高速缓存进行写入-这将使您的插入速度非常快。
  3. Run all the inserts in one query as suggested by Manu 按照Manu的建议在一个查询中运行所有插入

可能不是最好的解决方案,但是您可以尝试构造一个查询字符串,例如INSERT INTO [table] VALUES (r1c1,r1c2,r1c3),(r2c1,r2c2,r2c3) ...并执行一个mysql_query (或者说一个查询几百行),甚至在构建sql查询时,如果不是来自受信任的来源,您甚至可以通过编程方式验证数据。

Parameterized queries by definition trade execution safety against reduced flexibility on the count of data items. 根据定义,参数化查询会牺牲执行安全性,以减少数据项计数的灵活性。

You have at least 2 possibilities to mitigate: 您至少有两种可能性可以缓解:

  • Build up the SQL, then execute it at once: 建立SQL,然后立即执行它:

Something like: 就像是:

$sql="INSERT INTO gadata (landing_page, page_title, page_views, visits, visitors, bounce_rate, pageviews_per_visit, time_on_page, avg_time_on_page, day, month, year, hour) VALUES ";
foreach ($all_data_rows as $data) {
  if ($i==0) $value=""; else $value=",";
  $sql.=$value."(:landing_page$i, :page_title$i, :page_views$i, :visits$i, :visitors$i, :bounce_rate$i, :pageviews_per_visit$i, :time_on_page$i, :avg_time_on_page$i, :day$i, :month$i, :year$i, :hour$i)";
  $i++;
}
$i=0;
$q=$db_handler->prepare($sql);
foreach ($all_data_rows as $data) {
  foreach ($data as $k => $v) {
    $q->bindValue(":$k$i", $v);
  }
  $i++;
}
$q->execute();
  • Use a temporary table to avoid locking and disk overhead 使用临时表以避免锁定和磁盘开销

First create a temporary table of type HEAP with the same structure as your target table, then insert into it: This will be much faster, as no locking and disk IO happens. 首先创建一个具有与目标表相同结构的HEAP类型的临时表,然后将其插入其中:这将更快,因为不会发生锁定和磁盘IO。 Then run 然后跑

INSERT INTO final_table SELECT * FROM temporary_table

If mitigation doesn't suffice, you will need to consider using non-parameterized queries for this use case. 如果缓解措施不足,则需要针对此用例考虑使用非参数化查询。 The usual caveats apply. 通常需要注意的事项。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM