现在我试图优化一些代码..
将大数据插入表格的更好方法是什么?
请考虑此代码正在运行。
$arrayOfdata = execute query (SELECT c.id FROM table1 )
从table1获取所有数据,将其存储到数组并将其插入表中。
private function insertSomeData($arrayOfdata, $other_id){
foreach($arrayOfdata as $data){
INSERT INTO table (
other_id,
other2_id,
is_transfered
) VALUES ('.$other_id.', '.$data['id'].', 0)'
}
}
我知道如果table1中有500k的数据,这段代码非常慢。所以我尝试了这样的东西..我把所有的一个sql查询
INSERT INTO
table (
other_id,
other2_id,
is_transfered
)
SELECT
"other_id", c.id, 0
FROM table1
我读到要插入的大量数据导致mysql减速或超时。 我在本地计算机上尝试了500k数据的代码,运行良好..
如果要插入大数据,是否会导致问题?更快插入的其他方法,不会导致服务器使用太多资源?
答案 0 :(得分:2)
用于插入大量记录,您应该考虑批量插入而不是为每行调用插入。
像
INSERT INTO [Table] ([Column List])
VALUES ([Value List 1])
, ([Value List 2])
, [...]
, ([Value List N]);
您可以使用循环生成查询,并附加每个记录,直到计数器达到批量大小。然后,一旦达到批量大小,触发mysql插入并重置计数器。
此外,如果数据太多并且您只需要将其迁移到新表,您可以考虑将查询附加到db.sql
文件中并通过sql控制台直接转储,如
USE newdb
SOURCE db.sql
答案 1 :(得分:1)
您绝对不希望将所有数据从第一个表提取到客户端,然后逐行插入目标表。
我建议使用INSERT INTO ... SELECT FROM ...
语法将数据从一个表传输到另一个表。
如果要批量传输数据,可以始终在SELECT LIMIT
中使用OFFSET
子句。
另一种方法是首先使用SELECT ... INTO OUTFILE
将所需数据转储到文件中,然后使用LOAD DATA INFILE
将其加载到另一个表中。如果文件太多而无法立即加载,则可以拆分文件。
在传输数据时,还要确保目标表没有任何索引。完成转移后,创建所有必要的索引。
答案 2 :(得分:1)
根据我的经验,将大量数据导入MySQL表的最快方法是通过文件。如果数据很大,那么“插入...选择......”可能因为潜在的内存压力而超时 - 我已经看到了这种情况。但是,将数据从一个表转储到一个文件中,然后通过同一个文件将其随后加载到另一个表中,可以顺利运行,并且可能是使用大型数据集的最快方法。
要将数据选择到文件中,请参阅this.
要从文件加载数据,请查看this。
希望这有帮助。
答案 3 :(得分:0)
以下列出的方法可用于插入大量数据
答案 4 :(得分:0)
尝试以较小的部分作为后台工作。 例如,将记录数量限制为,即100个记录。 然后每2分钟从crontab运行一次脚本。这将需要更长的时间,但你不会卡住服务器,在你的迭代之间服务器将正常运行。 100条记录和2分钟是可配置的参数,您必须为它们找出最佳值。
答案 5 :(得分:0)
您可以通过单个查询插入所有数据。这个查询在mysql上运行一次。
试试吧。
private function insertSomeData($arrayOfdata, $other_id){
$sql1 = "INSERT INTO table (
other_id,
other2_id,
is_transfered
) VALUES "; // initial query string
$sql2 = '';
foreach($arrayOfdata as $data){
$sql2 .= "('".$other_id."', '"..$data['id']."', '0'),"; // add value to query string
}
$sql2 = mb_substr($sql2, 0, -1); //remove last comma
$sql = $sql1.$sql2; //build full query
mysql_query($sql); //execute query. I suggest you to use mysqli_* or PDO. Because mysql_* is deprecated.
}
答案 6 :(得分:-1)
假设您正在使用InnoDB引擎(在最新的MySQL版本中是默认的),您应该只使用事务:将您的插入循环包装到BEGIN;
... COMMIT;
块中。
默认情况下,每个语句都作为事务运行,并且服务器必须确保数据在继续下一个语句之前安全地将其安装到磁盘。如果启动事务,然后执行许多插入,然后提交事务,则服务器必须将所有数据刷新到磁盘上。在现代硬件上,这可能只占很少的磁盘操作而不是500k。
另一个考虑因素是use prepared statements。服务器必须在执行之前解析每个SQL语句。这种解析不是免费的,并且解析时间可能比实际查询执行时间更昂贵并不罕见。通常,这种解析每次都会完成,对于你的情况,它完成了500k次。如果使用预准备语句,则解析/准备只执行一次,执行语句的成本仅为磁盘写入(如果您在活动事务中,则会进一步增强,因为服务器可以通过延迟写入来批处理,直到事务提交为止)。 / p>
使用这些方法的总体改进可能非常显着 - 我已经看到使用交易时的总运行时间从30分钟缩短到20秒。
This answer应该知道如何在PHP中使用MySQL中的事务。