1

现在我试图优化一些代码..

将大数据插入表的更好方法是什么?

考虑此代码正在运行。

$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)'
            }
    }

我知道表 1 中是否有 500k 的数据,此代码非常慢。所以我尝试了这样的事情..我把所有的东西都放在一个 sql 查询中

INSERT INTO 
table (
    other_id,
    other2_id,
    is_transfered
) 
SELECT 
    "other_id", c.id, 0 
FROM table1 

我读到要插入的大量数据会导致 mysql 变慢或超时。我在本地计算机上的 500k 数据上尝试了此代码,它运行良好..

如果插入大数据,有什么方法会导致问题?其他更快插​​入不会导致服务器使用太多资源的方法?

4

7 回答 7

3

对于插入大量记录,您应该考虑分批插入它们,而不是为每一行调用 insert。

喜欢

INSERT INTO [Table] ([Column List]) 
       VALUES ([Value List 1])
            , ([Value List 2])
            , [...]
            , ([Value List N]);

更新到下面的评论

您可以使用循环生成查询,并附加每条记录,直到计数器达到批量大小。然后,一旦达到批量大小,就会触发 mysql 插入并重置计数器。

此外,如果数据太多而您只需要将其迁移到新表,您可能会考虑将查询附加到db.sql文件中并直接通过 sql 控制台将其转储,例如

USE newdb
SOURCE db.sql
于 2013-09-28T04:44:47.847 回答
1

绝对不想将所有数据从第一个表中提取到客户端,然后逐行插入目标表中。

我建议使用INSERT INTO ... SELECT FROM ...将数据从一个表传输到另一个表的语法。如果您想批量传输数据,您始终可以LIMIT在 SELECT 中使用子句OFFSET

另一种方法是先将您需要的数据转储到一个文件中SELECT ... INTO OUTFILE,然后再将LOAD DATA INFILE其加载到另一个表中。如果一次加载太多,您可以拆分文件。

还要确保您的目标表在传输数据时没有任何索引。完成传输后,创建所有必要的索引。

于 2013-09-28T05:02:19.923 回答
1

根据我的经验,将大量数据导入 MySQL 表的最快方法是通过文件。如果数据很大,“插入...从...中选择”可能会由于潜在的内存压力而超时——我已经看到这种情况发生了。但是,将数据从一个表转储到一个文件中,然后通过同一个文件将其加载到另一个表中可以顺利进行,并且可能是处理大型数据集的最快方法。

要将数据选择到文件中,请参阅此。

要从文件加载数据,请查看.

希望这可以帮助。

于 2013-09-28T05:58:22.753 回答
0

以下方法列表可用于插入大量数据

  1. 在开始插入之前尝试锁定表,然后解锁。
  2. 禁用 MySQL 索引。
  3. 扩展插件也可以在这里为您提供帮助。
于 2013-09-28T05:01:59.260 回答
0

尝试以较小的部分作为后台工作。例如,将记录数限制为 100 条记录。然后每 2 分钟从 crontab 运行一次脚本。这将花费更长的时间,但您不会卡住服务器,在您的迭代之间服务器将正常运行。100 条记录和 2 分钟是可配置的参数,您必须为它们找出最佳值。

于 2013-09-28T05:03:46.323 回答
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.  
    }
于 2013-09-28T05:50:37.650 回答
-1

假设您正在使用 InnoDB 引擎(这是最新 MySQL 版本中的默认引擎),您应该简单地使用事务:将您的插入循环包装到BEGIN;...COMMIT;块中。

默认情况下,每条语句都作为事务运行,服务器必须确保数据在继续执行下一条语句之前安全地存储到磁盘。如果您启动事务,然后执行多次插入,然后提交事务,那么服务器必须将所有数据刷新到磁盘上。在现代硬件上,这可能只相当于很少的磁盘操作,而不是 500k。

另一个考虑是使用准备好的语句。服务器必须在执行之前解析每个 SQL 语句。这种解析不是免费的,解析时间可能比实际查询执行时间更昂贵并不罕见。通常,此解析每次都会完成,对于您的情况,它会完成 500k 次。如果您使用准备好的语句,则解析/准备只完成一次,并且执行语句的成本只是磁盘写入(如果您处于活动事务中,则会进一步增强,因为服务器可以通过延迟写入直到事务提交来批量写入)。

使用这些方法的总体改进可能是巨大的——我见过使用事务将总运行时间从 30 分钟减少到 20 秒的情况。

这个答案应该给出一些想法,如何在 PHP 中使用 MySQL 中的事务。

于 2013-09-28T05:59:38.360 回答