Php 在处理大量信息时,如何优化数据库插入时间?

Php 在处理大量信息时,如何优化数据库插入时间?,php,codeigniter,optimization,cron,bulkinsert,Php,Codeigniter,Optimization,Cron,Bulkinsert,我有一系列的txt文件,里面有大约200人的信息。该信息每天生成和导出5或6次。每个txt文件平均每个有800行 我设置了一个cron(从php命令行)调用codeigniter控制器,使这个过程: 构造函数负载模型 从文件夹中获取txt文件、从文件名中删除空格和特殊字符并重命名的方法 返回存储在数组中的文件路径 另一个方法循环文件数组并调用$this->process($file) process()读取文件中的每一行 忽略空行并从每行生成一个数组,每行中都有值,读取:array_filte

我有一系列的txt文件,里面有大约200人的信息。该信息每天生成和导出5或6次。每个txt文件平均每个有800行

我设置了一个cron(从php命令行)调用codeigniter控制器,使这个过程:

  • 构造函数负载模型
  • 从文件夹中获取txt文件、从文件名中删除空格和特殊字符并重命名的方法
  • 返回存储在数组中的文件路径
  • 另一个方法循环文件数组并调用$this->process($file)
  • process()读取文件中的每一行
  • 忽略空行并从每行生成一个数组,每行中都有值,读取:array_filter(preg_split('/\s+/',$line))
  • 最后它调用model->insert\u line($line)
我怎样才能:

1-优化代码,以便我可以降低每个cron调用的2分钟(平均)执行时间?每个执行过程有5/6个txt文件和800avg。各行

2-设置MySQL表,以便它可以容纳大量记录,而不存在任何问题?存储的字段是2:“code”int(2)和“fecha”timestamp,在唯一索引(code,fecha)中设置


我有一台快速PC,并且表设置为InnoDB

您应该分析代码以确定瓶颈在哪里

您可能可以通过分解IO和CPU任务来加快速度。让多个进程执行IO没有任何意义,除非您已经将文件保存到多个磁盘或类似的东西上,因此,将一个IO进程用于将文件读入内存并将其放入队列中;然后,您可以让多个CPU进程从队列中提取文件并对其进行处理。如果可能(即,如果您有足够的RAM),将处理后的数据添加到内存队列中,当IO进程完成将所有文件读入内存后,您可以让它将处理后的数据写回磁盘;如果没有足够的RAM将文件和处理后的数据存储在内存中,那么让IO进程在读写之间交替进行。你应该运行足够的CPU进程来利用你的硬件线程,这可能是你的CPU上的内核数,或者如果你的CPU和操作系统支持超线程,那么内核数*2——用不同数量的进程运行一些计时实验,以获得一个好的数字


如果您分析代码并发现IO是问题所在,那么请查看是否可以在第一次生成文件时将文件保存到两个zip文件中-这将减少从磁盘读取的数据量,并使其更加连续,解压数据时需要额外的CPU处理。

第一种方法

您是否尝试过:

$this->db->insert_batch('table', $data);
其中,$data是包含要插入的对象/信息的数组。我不知道该方法的内部结构(尽管查看代码应该不难),但我几乎可以肯定,该方法在单个事务中完成了整个插入

您现在通过为每一行调用insert来执行此操作的方式意味着打开套接字/连接、执行检查以及每个事务需要执行的所有操作。因此,在这些情况下,执行大容量插入是一种方法,而CI中的函数正是这样做的,这意味着它将生成一个insert命令,该命令将在同一事务上执行

如果其中一个插入失败,您甚至可以回滚它,以便生成这些文件的人员可以处理或修复数据

第二种方法

如果您知道这些文件有一种特定的格式,那么您可以很容易地使用mysql中的实用程序,它将比您自己编写的任何工具都具有更好的性能

它的美妙之处在于,你可以用以下方式来称呼它:

$this->db->query($bulk_insert_command);
其中$bulk_insert_命令实际上是一个字符串,具有以下内容:

LOAD DATA [LOW_PRIORITY | CONCURRENT] [LOCAL] INFILE 'file_name'
    [REPLACE | IGNORE]
    INTO TABLE tbl_name
    [CHARACTER SET charset_name]
    [{FIELDS | COLUMNS}
        [TERMINATED BY 'string']
        [[OPTIONALLY] ENCLOSED BY 'char']
        [ESCAPED BY 'char']
    ]
    [LINES
        [STARTING BY 'string']
        [TERMINATED BY 'string']
    ]
    [IGNORE number {LINES | ROWS}]
    [(col_name_or_user_var,...)]
    [SET col_name = expr,...]
如上面提供的链接所示。当然,您会有一个函数来清理这个字符串,替换文件名和选项以及您需要的任何内容

最后,确保在CI应用程序的database.php中设置的任何用户都具有文件角色权限:

GRANT FILE on *.* TO user@localhost IDENTIFIED  BY 'password';

以便CI应用程序在运行此类查询时不会生成错误。

您是否可以控制文本文件的创建方式?如果你在一台多核机器上运行,我会把它分成每个核一个进程,你有没有理由必须使用CodeIgniter这样做?为什么不删掉中间人?我无法控制文本文件的生成方式。这是由第三方私有解决方案完成的。我必须使用CodeIgniter,因为它是团队用来开发整个项目的框架。除非我单独写一个剧本,但我只知道菲菲·古斯塔沃。我最终通过使用codeigniter事务$this->db->trans_start()解决了我的问题$这个->数据库->查询('一个SQL查询…')$这个->数据库->查询('另一个查询…')$这个->数据库->查询('还有另一个查询…')$此->数据库->传输完成();很高兴听到它起作用了!事务是获取大量数据的方式!萨卢多斯!