大型insert语句系列上的PHP mySQL性能问题,我应该使用其他语句吗?

大型insert语句系列上的PHP mySQL性能问题,我应该使用其他语句吗?,php,mysql,csv,loops,Php,Mysql,Csv,Loops,我有一个脚本,可以编译一个很长的项目列表-只需编译这个列表可能需要10-15分钟,但这是可以接受的。当我合并一个遍历列表并将它们全部插入mySQL表的函数时,时间大约增加了50%。我想知道是否有更快的方法来序列化这些数据?我应该探索CSV还是其他什么?或者我可以优化代码以更快地完成此操作: private function toDB(){ $sql[] = "DROP TABLE IF EXISTS checklisttest";$sql[] = "CREATE TABLE ch

我有一个脚本,可以编译一个很长的项目列表-只需编译这个列表可能需要10-15分钟,但这是可以接受的。当我合并一个遍历列表并将它们全部插入mySQL表的函数时,时间大约增加了50%。我想知道是否有更快的方法来序列化这些数据?我应该探索CSV还是其他什么?或者我可以优化代码以更快地完成此操作:

    private function toDB(){
    $sql[] = "DROP TABLE IF EXISTS checklisttest";$sql[] = "CREATE TABLE checklisttest (
  Incident varchar(12) NOT NULL,
  TestID mediumint(9) NOT NULL AUTO_INCREMENT,
  Element varchar(12) NOT NULL,
  Name varchar(128) NOT NULL,
  Code varchar(512) NOT NULL,
  Expected varchar(512) NOT NULL,
  Actual varchar(512) NOT NULL,
  AutoVerifyResult varchar(32) NOT NULL,
  QAResult varchar(32) DEFAULT NULL,
  Comments text,
  PRIMARY KEY (TestID)
)";

    //iterate through the records $this->records[10001] -- There can be anywhere from 100 - 300 records
    foreach($this->records as $inc => $record){
        //iterate through the element ids $this->records[10001][E02_04]
        foreach($this->records[$inc]["Elements"] as $elementID => $element){
            //iterate through the element ids $this->records[10001][E02_04][1] --There can be anywhere from 150 - 350 elements per record.
            foreach($element as $key => $val){
                $sql[] = "
INSERT INTO `checklistTest` VALUES (\"$inc\",NULL,\"$elementID\",\"$val[name]\",\"$val[code]\",\"$val[expected]\",\"$val[actual]\",\"$val[match]\",\"$val[QAResult]\",NULL)";
            }
        }
    }
    foreach($sql as $key => $val){
        mysql_select_db("new",$GLOBALS['local']);
        mysql_query($val,$GLOBALS['local']) or die(mysql_error());
    }
    //echo "<textarea style='width:100%;height:400px'>$sql</textarea>";
    //mysql_select_db("new",$GLOBALS['local']);
    //mysql_query($sql,$GLOBALS['local']) or die(mysql_error());
}
private函数toDB(){
$sql[]=“如果存在,则删除表checklisttest”;$sql[]=“创建表checklisttest”(
事件varchar(12)不为空,
TestID mediumint(9)非空自动增量,
元素varchar(12)不为空,
名称varchar(128)不为空,
代码varchar(512)不为空,
应为varchar(512)不为空,
实际varchar(512)不为空,
自动验证结果varchar(32)不为空,
QASULT varchar(32)默认为空,
评论案文,
主键(TestID)
)";
//遍历记录$this->records[10001]——可以有100-300条记录
foreach($this->记录为$inc=>$record){
//迭代元素ID$this->记录[10001][E02\u 04]
foreach($this->将[$inc][“元素”]记录为$elementID=>$element){
//迭代元素ID$this->records[10001][E02_04][1]——每个记录可以有150-350个元素。
foreach($key=>$val的元素){
$sql[]=”
在“checklistTest”值中插入(\“$inc\”,NULL,\“$elementID\”,\“$val[name]\”,\“$val[code]\”,\“$val[expected]\”,\“$val[actual]\”,\“$val[match]\”,\“$val[qasult]\”,NULL)”;
}
}
}
foreach($sql作为$key=>$val){
mysql_select_db(“新的,$GLOBALS['local']);
mysql_query($val,$GLOBALS['local'])或die(mysql_error());
}
//回显“$sql”;
//mysql_select_db(“新的,$GLOBALS['local']);
//mysql_query($sql,$GLOBALS['local'])或die(mysql_error());
}
必须有更好的方法来做这件事,我只是没有太多的经验来执行很多这样的查询-通常它们只是一个,为我做的。谢谢你的帮助


感谢您的回答,我将我的解决方案发布在对已接受答案的评论中。

插入触发多个插入语句您可以将它们组合到一个查询中,如下所示-

$sql=“插入
checklistest
VALUES”

注意:现在删除最后一个逗号。也就是说,对于数组中的最后一个值,将在末尾附加一个逗号。请删除该逗号,否则将出现数据库错误。

现在,由于上述插入查询的合并,您只需查询数据库一次,这大大提高了查询性能

mysql_select_db(“新的,$GLOBALS['local'])

mysql_query($sql,$GLOBALS['local'])或die(mysql_error())

//echo“$sql”;
//mysql_select_db(“新的,$GLOBALS['local']);
//mysql_query($sql,$GLOBALS['local'])或die(mysql_error());
}

有关此方法的详细文档,请参阅以下链接-


影响性能的因素有很多,包括服务器硬件、平均负载、MySQL设置、内存使用等。我将盲目地假设您存在I/O瓶颈,并且MySQL已针对您施加的负载进行了正确配置

让我们使用准备好的语句和事务。我将在本例中使用,但如果您愿意,可以使用。只要停止使用陈旧的mysql扩展就行了

$pdo->beginTransaction();
$statement = $pdo->prepare('
    INSERT INTO checklistTest
           VALUES(?, NULL, ?, ?, ?, ?, ?, ?, ?, NULL)
');
foreach($this->records as $inc => $record){
    foreach($this->records[$inc]["Elements"] as $elementID => $element){
        foreach($element as $key => $val) {
            $statement->execute(array(
                $inc,
                $elementID,
                $val['name'],
                $val['code'],
                $val['expected'],
                $val['actual'],
                $val['match'],
                $val['QAResult']
            ));
        }
    }
}
$pdo->commit();
那么,这里发生了什么?首先,我们要开始一个新的项目。我们告诉数据库我们将要做一系列的工作,我们要么要全部完成,要么什么都不做

其次,我们正在准备一个SQL语句。看到那些问号了吗?这些被称为占位符。稍后,我们将告诉数据库在每个占位符处填写特定数据。还请注意,没有引号。这些基本上是在占位符被填充时自动添加的

在循环内部,我们告诉语句执行,并为占位符传入一个值数组。有些人喜欢这样做,但我更喜欢数组方法

在循环中重复的准备好的语句可能比未准备好的语句要快,尽管除非您运行成千上万个查询(听起来像是这样),否则差异不会太明显

最后,循环完成后,我们告诉数据库提交我们刚刚完成的工作。正如我在评论中提到的,这就是性能大幅度提升的可能性所在。当您执行提交时,数据库实际上只会将更改永久写入磁盘。这意味着正常的簿记任务可以等到提交发生,而不需要在每次插入时都执行。这样,在运行insert时,所需的大部分I/O不需要实时发生

如果你使用这种技术,你还需要做一个改变。多年来,MySQL被配置为默认情况下不创建事务安全表。这意味着我们需要实际更改您的
CREATE TABLE
语句:

CREATE TABLE checklistTest (
   ... // No changes inside
) ENGINE=InnoDB
唯一的区别是在结束时,在结束后。我们要求使用MySQL,而不是服务器默认值。这保证了我们将得到一个支持事务的表

现在,我意识到要求您更改数据库适配器可能有点愚蠢,但这并不是没有理由的。虽然您可以使用oldschool mysql接口执行事务(通过自己发出
START TRANSACTION
COMMIT
/
ROLLBACK
命令),但您不能对其使用准备好的语句。虽然这本身并不是一个交易破坏者,但prepare-bind-execute过程是每个现代PHP数据库适配器都遵循的过程。旧的
//echo "<textarea style='width:100%;height:400px'>$sql</textarea>";
//mysql_select_db("new",$GLOBALS['local']);
//mysql_query($sql,$GLOBALS['local']) or die(mysql_error());
$pdo->beginTransaction();
$statement = $pdo->prepare('
    INSERT INTO checklistTest
           VALUES(?, NULL, ?, ?, ?, ?, ?, ?, ?, NULL)
');
foreach($this->records as $inc => $record){
    foreach($this->records[$inc]["Elements"] as $elementID => $element){
        foreach($element as $key => $val) {
            $statement->execute(array(
                $inc,
                $elementID,
                $val['name'],
                $val['code'],
                $val['expected'],
                $val['actual'],
                $val['match'],
                $val['QAResult']
            ));
        }
    }
}
$pdo->commit();
CREATE TABLE checklistTest (
   ... // No changes inside
) ENGINE=InnoDB