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

时间:2014-02-12 21:05:33

标签: php codeigniter optimization cron bulkinsert

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

我设置了一个cron,它调用(来自php命令行)一个执行此过程的codeigniter控制器:

  • 构造函数加载模型
  • 一个方法从文件夹中获取txt文件,从文件名中删除空格和特殊字符并重命名
  • 返回存储在数组中的文件路径
  • 另一种方法循环遍历文件数组并调用$ this-> process($ file)
  • process()从文件中读取每一行
  • 忽略空白行并从每行构建1个数组,每行读取数值:array_filter(preg_split('/ \ s + /',$ line));
  • 最后它调用了model-> insert_line($ line)

我怎么能:

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

2-设置MySQL表,以便它可以容纳非常大的qtty记录而不用麻烦?存储的字段是2:“code”int(2)和“fecha”时间戳,在唯一索引(代码,fecha)中设置

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

2 个答案:

答案 0 :(得分:1)

您应该分析您的代码以确定瓶颈的位置。

您可以通过拆分IO和CPU任务来加快速度。除非你已经将文件保存到多个磁盘或这些行中的某些内容,否则让多个进程执行IO是没有意义的,所以专门用一个IO进程将文件读入内存并将它们放入队列中;然后你可以有多个CPU进程从队列中提取文件并处理它们。如果可能(例如,如果你有足够的RAM),将这个处理过的数据添加到内存中队列,当你的IO进程完成将所有文件读入内存后,你可以让它将处理后的数据写回磁盘;如果没有足够的RAM将文件+已处理的数据存储在内存中,则IO进程在读写之间交替。您应该运行足够的CPU进程来利用您的硬件线程,这可能是您在CPU上拥有的核心数量,或核心数量* 2,如果您的CPU和操作系统支持超线程 - 使用各种数字进行一些计时实验达到一个好数字的过程。

如果您对代码进行了分析并发现IO是问题所在,那么看看您是否可以执行某些操作,例如在首次生成时将文件保存为几个zip文件 - 这将减少您的数据量从磁盘读取并且还会使其更连续,代价是在解压缩数据时需要额外的CPU处理。

答案 1 :(得分:0)

第一种方法

你试过了吗?

$this->db->insert_batch('table', $data);

其中$ data是包含要插入的对象/信息的数组。我不知道该方法的内部(虽然查看代码应该不难)但我几乎可以肯定这个方法在单个事务中完成整个插入。

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

如果其中一个插入失败,您甚至可以回滚它,这样生成这些文件的人就可以按摩或修复数据。

第二种方法

如果您知道这些文件具有特定格式,您可以轻松使用mysql中的LOAD DATA INFILE实用程序,它将比您自己编写的任何工具具有更好的性能。

它的美妙之处在于你可以用它来调用它:

$this->db->query($bulk_insert_command);

其中$ bulk_insert_command实际上是一个类似于:

的字符串
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应用程序在运行此类查询时不会生成错误。