jotagp/insert-multiple

一个简单的PHP包,用于将多个记录插入MySQL/MariaDB数据库。

v1.2 2023-06-07 00:39 UTC

This package is auto-updated.

Last update: 2024-09-23 18:28:00 UTC


README

摘要

  1. 介绍
    1.1 什么是
    1.2 为什么
    1.3 许可证
  2. 开始使用
    2.1 依赖项
    2.2 安装
    2.3 使用
    2.4 方法
    2.5 示例
  3. 享受

1. 介绍

1.1 什么是
这是一个简单的PHP包,可以将多个数据插入MySQL/MariaDB数据库。

1.2 为什么
创建此包的目的是为了减少数据插入时间。为了理解问题的严重性,让我们假设我们想要遍历一个列表中的项并将它们插入到数据库中。

// example with tradicional insert
foreach ($list as $item) {
	$insert = "INSERT INTO `table1`(`numbers`, `description`) VALUES ({$item['number']}, '{$item['description']}');
	$connection->query($insert) or die ($connection->error);
}

上面的例子是可行的。然而,当处理大量数据时,传统的插入方法并不可行。这是因为它一次只插入一条记录。所以,如果你有100,000条记录,将有100,000次插入,相应地,将有100,000次硬盘访问以持久化这些数据,这将花费很长时间(当然,这取决于你的数据大小)。一个“方法”是手动控制数据库的事务,如下所示:

// example with tradicional insert and transaction control
$connection->begin_transaction();
foreach ($list as $item) {
	$insert = "INSERT INTO `table1`(`numbers`, `description`) VALUES ({$item['number']}, '{$item['description']}');
	$connection->query($insert) or die ($connection->error);
}
$connection->commit();

然而,这种方法仍然不能从根本上解决我们的问题,因为时间上的节省并不显著。那么我们该怎么办呢?简单!进行多次插入

// example with manually multiple insert
$connection->begin_transaction();
$insert = "INSERT INTO `table1`(`numbers`, `description`) VALUES ";
foreach ($list as $item) {
	$values[] = "({$item['number']}, '{$item['description']}')"; // concat new values 
}
$insert .= implode(", ", $values); // join values separete by comma
$connection->query($insert) or die ($connection->error);
$connection->commit();

然而(总是有一个“然而”,对吧?),银行允许的交易限制,当设置一个非常广泛的查询时,这个限制很容易达到。这就是这个包发挥作用的地方。它将根据银行的能力将你的值分成N个多次插入槽位

// example with package
$insert = new insert_multiple($connection, "table1");
foreach ($list as $item) {
	$insert->push($item); // concat new values
}
$insert->exec(); // run inserts

就这么简单。

1.3 许可证
此代码受MIT许可证许可。

2. 开始使用

2.1 依赖项
此库只依赖于

2.2 安装
运行以下命令

composer require jotagp/insert-multiple  

2.3 使用
将依赖项包含到你的PHP项目中

require 'vendor/autoload.php';
use jotagp\insert_multiple\insert_multiple;
$connection = new mysqli('host', 'user', 'pass', 'database');
$insert_multiple = new insert_multiple($connection, 'table-name');

2.4 方法
有三种可能的方法

push($associative_array)
此方法用于将新值包括在插入中。请注意,预期的参数是一个关联数组,其中数组的索引必须始终引用要插入的表的属性。未指定的属性将使用各自的默认值。

exec()
此方法将你的插入分割成N个多次插入,然后运行,始终考虑你的数据库实例允许的事务量(max_allowed_package)。也就是说,在一个包含100万条记录的插入中,假设函数将创建10个多次插入,每个插入10万条记录。

config($associative_array)
此方法允许你编辑对象的一些行为。可能的配置(目前)有

  • update_if_exists: 如果存在相应的键,则更新记录。
    • fields_to_update: 在update_if_exists内部,你可以指定应更新的哪些字段。
    • concat_new_values: 允许将新值连接到现有值。
    • skip_if_already_exists: 保留已存在的值,忽略新值。
    • skip_if_new_is_empty: 如果新的值为空或为null,则保留已存在的值。
  • insert_multiple: 如果为false,则每次插入一条记录。

2.5 示例
将10万条随机数据插入数据库。考虑以下数据结构

DROP DATABASE IF EXISTS `0temp`;
CREATE DATABASE `0temp`;
USE `0temp`;

DROP TABLE IF EXISTS `table1`;
CREATE TABLE `table1` (
  `number` int(11) NOT NULL AUTO_INCREMENT,
  `description` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`number`)
)

然后

<?php

require  'vendor/autoload.php';
use  jotagp\insert_multiple\insert_multiple;

$connection = new mysqli('localhost','root', 'root', '0temp') or die($connection->error);
$insert_multiple = new  insert_multiple($connection, 'table1');

// generate randon numbers, between 1 and 1000
$count =  0;
while ($count < 100000) {

	$list[] = ['value' => rand(1, 1000)];
	$count +=  1;
	
}

// insert multiple
echo  "\nStart at: ".  Date('Y-m-d H:i:s') .  "\n[ ";
$count =  0; // for print a simple log
foreach ($list as $key => $item) {

	$table1 = []; // clean the associative array
	$table1['number'] = $key; // the 'number' index, matches the database attribute
	$table1['descriptions'] = $item['value']; // the 'number' index, matches the database attribute

	// magic is here
	$insert_multiple->push($table1); // push the associative array 

	$count += 1;
	if ($count % 1000 ==  0) echo "#";
	if ($count % 10000 ==  0) echo " ". $count ." ";
	
}
// magic is here two
$insert_multiple->exec();


// update multiple
$update_multiple = new insert_multiple($connection, 'table1');
$update_multiple->config([
  'update_if_exists' => [
    'fields_to_update' => [
      'description'
    ]
    // 'concat_new_values' => true,
    // 'skip_if_already_exists' => true,
    // 'skip_if_new_is_empty' => true
  ]
]);
echo  "\nStart at: ".  Date('Y-m-d H:i:s') .  "\n[ ";
$count =  0; // for print a simple log
foreach ($list as $key => $item) {

	$table1 = [];
	$table1['number'] = $key; // important! when you go update a row, remember set the key property (in this case, field number)
	$table1['descriptions'] = 'data updated by jotagp lib';

	$update_multiple->push($table1); 

	$count += 1;
	if ($count % 1000 ==  0) echo "#";
	if ($count % 10000 ==  0) echo " ". $count ." ";
	
}
$update_multiple->exec();

echo  "]\nfinished at: ".  Date('Y-m-d H:i:s') .  "\n";

?>

3. 享受

感谢您耐心阅读到这里。希望这个包能帮助您在日常工作中获得更好的性能。
如果您需要帮助或有任何建议,我随时为您服务。您可以通过LinkedIn联系我。