仅在实时服务器上升级到 PHP 7.1 后 CSV 导入超级慢

CSV Import Super Slow after upgrading to PHP 7.1 only on live server

我们将生产服务器升级到新服务器,我们从使用 PHP 5.6 到 PHP 7.1,我们在上面托管了一个 Drupal 7 网站。在大多数情况下,该站点似乎运行正常。服务器移动后我看到的问题是 CSV 导入与以前相比需要很长时间。 csv 导入将每一行添加到数据库中。

  $fp = fopen($file_path, 'r');
  if ($fp === FALSE) {
    // Failed to open file.
    watchdog('ea_test', 'Failed to open %file_path', array('%file_path' => $file_path));
    $context['finished'] = TRUE;
    return;
  }
  fseek($fp, $context['sandbox']['offset']);

  for ($i = 0; $i < $limit; $i++) {
    $line = fgetcsv($fp);

    if ($line == FALSE) {
      $done = TRUE;
    }
    // If first line just skipping ahead.
    elseif ($context['sandbox']['records'] < 1) {
      $context['sandbox']['records']++;
    }
    else {
      try {
        db_insert('ea_csv_test')
          ->fields(array(
            'agent_number' => $line[0],
            'total_signatures' => $line[1],
            'template_number' => $line[2],
            'photo' => $line[3] ? 1 : 0,
            'total_views' => $csv_line[4],
            'total_clicks' => $csv_line[5],
            'annual_cost' => $csv_line[7],
            'monthly_cost' => $csv_line[8],
            'popular_button' => $csv_line[9],
            'month' => $csv_line[10],
            'asof' => date('Y-m-d 00:00:00'),
          ))->execute();
      }
      catch (Exception $e) {
        // By setting the databse error it will fail and display the last bad
        // record. Normally I would log/email this but I think it
        // will send too many. More than likely if one is bad they all
        // will be bad.
        $database_insert_error = $e->getMessage();
        $error = TRUE;
      }

      // Set the current position of the file so it starts from there.
      $context['sandbox']['offset'] = ftell($fp);

      $context['sandbox']['records']++;
    }
  }

  $eof = feof($fp);

事情发生在本地和我的暂存站点上,我无法复制该问题。唯一的区别是我在本地使用 PHP 7.1.17,在生产环境使用 PHP 7.1.25。 local 和 prod 都在使用 mariadb 5.5.5-10.2.19-MariaDB-log.

时间比较:

本地/暂存处理需要 9.51 秒。

生产需要 276.12 秒来处理。

编辑

我 运行 直接从数据库导入(没有任何 PHP),速度非常快。在我看来,它必须是某种 php 设置:

truncate TABLE ea_csv_test;
LOAD DATA INFILE '/tmp/test.csv' into table ea_csv_test
FIELDS TERMINATED BY ',' 
ENCLOSED BY '"'
LINES TERMINATED BY '\n'
IGNORE 1 ROWS;

编辑 2

注意到未启用生产 APCu。我启用了它,它有点帮助。它从 276 秒变为 166 秒。

我开始比较 innodb 设置,我发现我在本地将 innodb_flush_log_at_trx_commit 设置为 2,但在生产中它设置为 1。一旦我在生产中将其更改为 2,它就解决了我的问题。

根据我的理解,如果设置为 2,它会每秒记录一次,而不是任何事务。最坏的情况是,如果服务器出现故障,我们可能会丢失 1 秒的数据。就我而言,如果我们正在导入并且服务器出现故障,我无论如何都需要重新上传,因为导入永远不会完成。我认为如果我们正在进行货币交易,将值保持在 1 是有意义的。