>我正在尝试创建一个脚本来将大约 10m 条记录导入 mysql 数据库。
当我使用单个查询进行循环时,导入 2000 条记录需要 20 分钟。
所以我正在尝试通过交易来做到这一点。问题是,在我的循环中,需要立即触发一些选择查询才能获取一些值来创建插入。最后两个查询(插入和更新)可能在事务中。
像这样:
foreach($record as $rec) {
//select sth
//do sth with result
//second select sth
//do sth with second result
//prepare values from above results and $rec
// below part I'd like to do with transaction
//insert with new record
//update table
}
我知道这有点混乱且不准确,但是这个功能更复杂,所以我决定只放一个"草稿",我只需要建议,而不是完整的代码。
问候
事务适用于多个语句,这些语句需要被视为完全成功或完全失败的单个组。听起来您的问题与性能有关,而不是事务。除非有一点你没有包含的信息涉及"所有语句必须同时成功"的语句组,否则交易只是分散注意力。
有几种方法可以解决您的问题,具体取决于您的帖子中一些不太明显的事情。-如果 10M 条记录的数据源是要用新记录填充的同一数据库中的表(通过循环末尾的插入和更新),那么您可以通过单个数据库查询执行所有操作。SQL非常富有表现力,通过连接和一些内置函数(SUBSTR(),UPPER(),REVERSE(),CASE...完,等等)你也许可以做你想做的一切。这需要阅读 SQL 并尝试根据您可以执行的集合操作来重新构建您的目标。-如果您要插入来自数据库外部(例如来自文件)的记录,那么我会像这样组织您的代码
//select sth
//do sth with result
//second select sth
//do sth with second result
//prepare values from above results so that $rec info can be added in later
foreach($record as $rec) {
//construct a big insert statement
}
//insert the new records by running the big insert statement
//update table
这里的优点是,您只使用几个查询来访问数据库,而不是每个查询几个查询$rec因此您的性能会更好(因为数据库调用有开销)。对于 10M 行,您可能需要将上述内容分解为几个块,因为单个插入的大小是有限制的(请参阅max_allowed_packet)。我建议通过在上面添加另一个循环来将 10M 分解为 5K 或 10K 块,从 10M 中分离出块。
如果您添加了有关数据源的详细信息,要对数据执行哪些转换,以及
//select sth
//do sth with result
//second select sth
//do sth with second result
部分(在稍后如何向插入语句添加信息的上下文中),以及代码的"准备值"部分的作用。