简体   繁体   English

关于大量插入语句的PHP mySQL性能问题,我应该使用别的吗?

[英]PHP mySQL performance issues on large series of insert statements, should I use something else?

I have a script that compiles a list of items that can be very long - just compiling this list can take 10-15 minutes, but that is acceptable. 我有一个脚本编译可能很长的项目列表 - 只需编译此列表可能需要10-15分钟,但这是可以接受的。 When I incorporate a function that iterates through the list and inserts them all into a mySQL table, that time is increased about about 50%. 当我合并一个遍历列表并将它们全部插入到mySQL表中的函数时,该时间增加了约50%。 I was wondering if there was a faster way of serializing this data? 我想知道是否有更快的方法来序列化这些数据? Should i explore CSV or something else? 我应该探索CSV或其他什么? Or can I optimize my code to do this faster: 或者我可以优化我的代码来更快地执行此操作:

    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());
}

There must be a better way to go about doing this, I just don't have much experience performing a lot of queries like this - usually they are just one-and-done for me. 必须有一个更好的方法去做这件事,我只是没有太多经验来执行这样的大量查询 - 通常它们对我来说只是一劳永逸。 Thanks for the help. 谢谢您的帮助。

thanks for the answers, I posted my solution in a comment to the accepted answer. 感谢您的回答,我在对已接受答案的评论中发布了我的解决方案。

There are a whole bunch of factors that impact performance, including server hardware, average load, MySQL settings, memory use, etc. I'm going to blindly assume that you have an I/O bottleneck and that MySQL is properly configured for the load you're putting on it. 影响性能的因素有很多,包括服务器硬件,平均负载,MySQL设置,内存使用等。我将盲目地假设你有一个I / O瓶颈并且MySQL 正确配置为负载你正在穿上它。

Let's use a prepared statement and a transaction. 让我们使用准备好的声明和交易。 I'll be using PDO in this example, but you could use mysqli if you want. 我将在此示例中使用PDO ,但如果需要,可以使用mysqli Just stop using the old and busted mysql extension. 只需停止使用旧的和破坏的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();

So, what's happening here? 那么,这里发生了什么? First, we're starting a transaction . 首先,我们正在开始交易 We're telling the database that we're about to do a bunch of work, and we either want it all done, or none of it. 我们告诉数据库我们要做一堆工作,我们要么全部完成,要么全部完成。

Second, we're preparing a SQL statement. 其次,我们正在准备一个SQL语句。 See those question marks? 看到那些问号? Those are called placeholders. 这些被称为占位符。 We'll later tell the database to fill in specific data at each placeholder. 我们稍后会告诉数据库在每个占位符处填写特定数据。 Also note that there are no quotation marks. 另请注意,没有引号。 Those are basically added automatically when the placeholders get filled in. 这些基本上是在占位符填写时自动添加的。

Inside the loop, we're telling the statement to execute, and we're using PDO's execute method to pass in an array of values for the placeholders. 在循环内部,我们告诉要执行的语句,我们正在使用PDO的execute方法传递占位符的值数组。 Some people prefer doing this one variable at time using bindParam , but I prefer the array method. 有些人喜欢使用bindParam一次做这个变量 ,但我更喜欢数组方法。

Prepared statements repeated in a loop can be faster than unprepared statements, though the difference won't really be noticeable unless you're running tens of thousands of queries, which is kind of sounds like you are. 在循环中重复的预处理语句可能比没有准备的语句更快,尽管除非你运行成千上万的查询,这种差异并不会显着,这听起来像你一样。

Finally, once the loop is finished, we tell the database to commit the work we've just done. 最后,一旦循环完成,我们告诉数据库提交我们刚刚完成的工作。 As I mentioned in the comments, that's where a big performance boost is possible. 正如我在评论中提到的那样,这可能会带来巨大的性能提升。 The database will only actually permanently write changes to disk when you perform the commit. 执行提交时,数据库实际上只会永久性地将更改写入磁盘。 This means that normal book-keeping tasks can wait until the commit happens, instead of needing to happen on every single insert. 这意味着正常的簿记任务可以等到提交发生,而不是需要在每个插入时发生。 This way, the bulk of the I/O you need doesn't need to happen live, as you run the insert. 这样,当您运行插入时,您需要的大部分I / O不需要实时发生。

There's one more change that you'd need to make if you use this technique. 如果您使用此技术,还需要进行一项更改。 For years, MySQL has been configured to not create transaction-safe tables by default. 多年来,MySQL已被配置为默认情况下创建事务安全表。 This means that we need to actually change your CREATE TABLE statement a bit: 这意味着我们需要实际更改您的CREATE TABLE语句:

CREATE TABLE checklistTest (
   ... // No changes inside
) ENGINE=InnoDB

The only difference is there at the end, after the close-paren. 唯一的区别是在最后,在关闭之后。 We're asking MySQL to use the InnoDB storage engine instead of whatever the server default is. 我们要求MySQL使用InnoDB存储引擎,而不是服务器默认的。 This guarantees that we'll get a table that supports transactions. 这保证了我们将获得一个支持事务的表。

Now, I realize that asking you to change database adapters might be a bit silly, but it's not without reason. 现在,我意识到要求你更改数据库适配器可能有点傻,但这并非没有道理。 While you can perform transactions using the oldschool mysql interface (by issuing START TRANSACTION and COMMIT / ROLLBACK commands yourself), you can't use prepared statements with it. 虽然您可以使用oldschool mysql接口执行事务(通过自己发出START TRANSACTIONCOMMIT / ROLLBACK命令),但您不能使用预处理语句。 While that alone isn't a deal-breaker, the prepare-bind-execute process is one that every modern PHP database adapter follows. 虽然这不仅仅是一个交易破坏者,但是prepare-bind-execute过程是每个现代PHP数据库适配器都遵循的过程。 The old mysql interface is not a modern PHP database adapter, and you really should give some serious consideration to switching to PDO or mysqli. 旧的mysql接口不是现代的PHP数据库适配器,你真的应该认真考虑切换到PDO或mysqli。


One more performance factor is actually how you gather the data you're about to write. 另一个性能因素实际上是如何收集您即将编写的数据。 While this answer focuses on making sure that the database itself is as small of a bottleneck as practical, it could be that your performance problem is earlier in the process . 虽然这个答案侧重于确保数据库本身尽可能小的瓶颈, 但可能是您的性能问题在此过程中更早 Can you tell us where this data comes from, and how you're building it? 您能告诉我们这些数据来自哪里,以及您如何构建它? You should seriously consider profiling your code , which will reveal the real performance problem. 您应该认真考虑分析您的代码 ,这将揭示真正的性能问题。 It could be that the database bits are already lightning-quick and the problem is somewhere else entirely. 可能是数据库位已经闪电般快速,问题完全在其他地方。

Insert of firing multiple insert statements you can combine them in to one query as below - 插入多个插入语句,您可以将它们组合到一个查询中,如下所示 -

 //iterate through the records $this->records[10001] -- There can be anywhere from 100 - 300 records 

$sql = "INSERT INTO checklistTest VALUES "; $ sql =“INSERT INTO checklistTest VALUES”;

  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.= "(\\"$inc\\",NULL,\\"$elementID\\",\\"$val[name]\\",\\"$val[code]\\",\\"$val[expected]\\",\\"$val[actual]\\",\\"$val[match]\\",\\"$val[QAResult]\\",NULL),"; } } } 

Note: Now here remove the last comma. 注意:现在删除最后一个逗号。 ie for the last value in array too a comma will be appended at the end do remove that else you will get database error. 即对于数组中的最后一个值,也会在末尾附加一个逗号,删除其他你将得到数据库错误。

Now because of above merging of insert queries you have to query your database only once which improves your query perfomance a lot. 现在由于上面插入查询的合并,你只需要查询一次数据库,这会大大提高你的查询性能。

mysql_select_db("new",$GLOBALS['local']); mysql_select_db( “新”,$ GLOBALS [ '本地']);

mysql_query($sql,$GLOBALS['local']) or die(mysql_error()); mysql_query($ sql,$ GLOBALS ['local'])或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());

} }

Your can refer below links for detailed documentation of this method - 您可以参考以下链接获取此方法的详细文档 -

http://www.brainbell.com/tutorials/MySQL/Inserting_Multiple_Rows.htm http://www.brainbell.com/tutorials/MySQL/Inserting_Multiple_Rows.htm

http://dev.mysql.com/doc/refman/5.5/en/insert.html http://dev.mysql.com/doc/refman/5.5/en/insert.html

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

相关问题 MySQL –我应该使用last_insert_id()吗? 或者是其他东西? - MySQL – Should I use last_insert_id()? or something else? 我应该在PHP PERFORMANCE-WISE中使用MySQL的预处理语句吗? - Should I use prepared statements for MySQL in PHP PERFORMANCE-WISE? 我应该在将mysql查询与三个IN语句或其他内容结合使用时使用AND吗? - Should i use AND while combining mysql query with three IN statements or something else? 我是否应该在PHP中使用嵌套的if ... else语句进行一系列小于比较 - Should I use nested if .. else statements for a series of less than comparisons in PHP 我应该在这个项目中使用Perl或PHP或其他东西吗? - Should I use Perl or PHP or something else for this project? 在PHP中,我应该使用正则表达式来匹配此内容还是其他内容? - In PHP should I use a regular expression to match on this or something else? 带插入的大型表上的mysql性能问题 - mysql performance issues on large tables with insert 我应该使用正则表达式,还是只使用一系列if语句? - Should I use regex, or just a series of if statements? MySQL PHP PDO准备语句 - 性能问题与安全性 - MySQL PHP PDO prepared statements - performance issues vs security 我应该使用哪种散列方法来处理大文本? - PHP / MYSQL - Which hashing method should I use for large text? - PHP / MYSQL
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM