MySQLi多行插入非常慢

问题描述 投票:0回答:5

我在WAMP中有一个InnoDB表,其中包含大约4千万条具有以下结构的记录:

CREATE TABLE sales (
  sale_id int(12) unsigned NOT NULL,
  sale_type_id int(12) unsigned NOT NULL,
  sale_employee_id int(12) unsigned NOT NULL,
  sale_period tinyint(3) unsigned NOT NULL,
  sale_minute tinyint(3) unsigned NOT NULL,
  sale_second tinyint(3) unsigned NOT NULL,
  sale_amount decimal(5,2) unsigned NOT NULL,
  PRIMARY KEY (sale_id, sale_type_id),
  KEY (sale_employee_id, sale_type_id, sale_period, sale_amount, sale_minute)
)

我正在使用MySQLi一次使用数组和“implode”一次性地插入大约3,000条新记录,如下所示,需要1到2分钟才能完成:

$insertArray = array();
foreach($phpArray->sales as $sale) {
    $saleId = (int) $saleId;
    $saleType = (int) $saleType;
    $saleEmployeeId = (int) $saleEmployeeId;
    $salePeriod = (int) $salePeriod;
    $saleMinute = (int) $saleMinute;
    $saleSecond = (int) $saleSecond;
    $saleAmount = $saleAmount;

    $insertArray[] = "('$saleId', '$saleType', '$saleEmployeeId', '$salePeriod', '$saleMinute', '$saleSecond', '$saleAmount')";
}

$insertSql = "INSERT IGNORE INTO sales (sale_id, sale_type_id, sale_employee_id, sale_period, sale_minute, sale_second, sale_amount) VALUES ".implode(",",$insertArray);
$insertResult = $mysqli->query($insertSql);

我这样做的方式有什么明显的错误吗?

INSERT IGNORE会明显慢于INSERT吗?我有复合PRIMARY KEY的事实可能是个问题吗?我是否需要在插入数组中的每个变量名称周围使用引号,如果没有,将删除它们会加快速度吗?

提前感谢任何建议!

php mysql mysqli wamp innodb
5个回答
1
投票

我有一个类似的问题。关闭自动提交并在一个请求中手动提交解决了我的问题。

$mysqli->autocommit(FALSE);
// loop through all the new records
foreach($newRecordsArray as $newRecord) {
... do your foreach loop per record here.....             
    $insertResult = $mysqli->query($insertSql);
}
//do one commit     
if (!$mysqli->commit()) {
    print("Transaction commit failed\n");
    exit();
}

0
投票

使用insert插入那么多行总是很慢。 Insert ignore只是通过跳过那些插入来忽略重复的错误,而不是抛出错误并停止整个批处理,所以这不是让它变慢的原因:插入那么多行是让它变慢的原因。

要快速插入那么多行,请在mysql控制台中使用load data infile,如果可以的话。

也可以使用PHP应用程序中的load data LOCAL infile,具体取决于用于连接MySQL的用户的权限。


0
投票

INSERT IGNOREINSERT更快。您可以直接连接字符串,而不是创建数组并对其进行插入。它应该更有效率。

在插入新行时,复合主键的成本比典型的id键略高,因为它基于MySQL(或哈希索引)中的B-TREE方法


0
投票

尝试改变:

$insertResult = $mysqli->query($insertSql);

至:

$mysqli->query("START TRANSACTION");
$insertResult = $mysqli->query($insertSql);
$mysqli->query("COMMIT");

这可能会让你大吃一惊:-)


0
投票

是的,当执行许多查询时,autocommit是有害的,请使用以下方法:

$mysqli->autocommit(FALSE);
$mysqli->begin_transaction(MYSQLI_TRANS_START_READ_WRITE);

// multiple inserts here

$mysqli->commit();

顺便说一句,您可以通过查询检查自动提交状态:

$mysqli->query("SELECT @@autocommit")
© www.soinside.com 2019 - 2024. All rights reserved.