循环查询越来越慢

时间:2011-01-28 21:57:15

标签: php mysql performance

我有一个逐行读取数据源的进程,解析并将数据插入到MyISAM表中。当它第一次启动时,它会非常快,大约每秒1000条记录。随着时间的推移,它变得越来越慢,现在我们每180秒大约有1行。

该函数的一般语法是:

function parse($file) {
  $handle = fopen($file, 'r');
  while (!feof($handle)) {
    $line = fgets($fileHandle, 1000);
    switch (substr($line, 0, 2)) { //gets record type
      case '01' :
        //parse the record
        //escapes some strings with mysql_real_escape_string()
        mysql_query('INSERT INTO table VALUES ($a, $b, $c...');
      case '02' :
        ...
    }
  }
}

正在解析的当前文件有几百万条记录。服务器似乎没有丢失内存空间。有人知道导致这个过程变慢的原因吗?

3 个答案:

答案 0 :(得分:6)

这可能与必须经常写入索引有关。您已经在使用MyISAM,这将是我的第一个建议。

一些建议

  1. 每100行批量插入
  2. 使用INSERT DELAYED允许MySQL允许插入快速完成排队,MySQL将在资源允许的情况下插入记录。
  3. 让您的脚本创建一个SQL转储/分隔文件,您可以使用IN FILE导入功能加载该文件,请参阅http://dev.mysql.com/doc/refman/5.1/en/load-data.html,这将比批量插入更快

答案 1 :(得分:3)

您可能在此表上至少有一个索引。因此每行都会插入越来越大的索引中。在开始加载之前,请执行

  

ALTER TABLE表DISABLE KEYS

完成后

  

ALTER TABLE表启用键

重新启用密钥可能需要一段时间。

加载时请勿尝试使用该表。此外,INSERT DELAYED可能有所帮助。但是,如果您在一个安静的数据库服务器上执行此表加载,可能不会。

答案 2 :(得分:1)

我认为你应该在事务中运行查询(它有加速),最好使用PDO因为它更安全。在PDO中准备好的声明可能会更快,但至少更安全,因为它们对SQL注入是无懈可击的。这种方式会快得多。我有一个准备好标签的例子:

<?php

$array = array(
    "ActionScript",
    "AppleScript",
    "Asp",
    "BASIC",
    "C",
    "C++",
    "Clojure",
    "COBOL",
    "ColdFusion",
    "Erlang",
    "Fortran",
    "Groovy",
    "Haskell",
    "Java",
    "JavaScript",
    "Lisp",
    "Perl",
    "PHP",
    "Python",
    "Ruby",
    "Scala",
    "Scheme"
);

function createTable($db) {
    $db->exec("CREATE TABLE IF NOT EXISTS tags (id INTEGER PRIMARY KEY, tag TEXT NOT NULL UNIQUE)");
}

function insertData($db, $array) {
    $db->beginTransaction();

    foreach($array as $elm) {
        try {
            $placeholder = array($elm);
            $stmt = $db->prepare("INSERT INTO tags (tag) VALUES (?)");
            $stmt->execute($placeholder);
        } catch(PDOException $e) {
            /*** roll back the transaction if we fail ***/
            $db->rollback();
            /*** echo the sql statement and error message ***/
            echo $sql . '<br />' . $e->getMessage();
        }
    }

    $db->commit();
}

$db = new PDO('sqlite:database/tags.sqlite3');
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, true);
//
createTable($db);
insertData($db, $array);

P.S:我还想指出InnoDB可能会更好。