Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/277.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php 解析和处理大型文件_Php_Mysql - Fatal编程技术网

Php 解析和处理大型文件

Php 解析和处理大型文件,php,mysql,Php,Mysql,我有一个大的CSV文件,我需要分为4部分,然后发送数据到数据库;我遇到的问题是CSV文件可能是1GB+(一次可能不止一个),这会造成各种时间延迟和内存问题 我想得到一些关于如何改进和加快流程的帮助 我正在测试的文件有45000条记录~10mb文件 现在我正在将文件加载到数组中,数组使用的大小大约是文件大小的3倍,所以对于10mb文件,我们说的是30mb内存;我希望通过逐行读取文件来减少对30mb内存的需求,但现在来看一下这个 处理部分相当简单,基本上我循环处理数据数组 最后一部分是将数据保存到数

我有一个大的CSV文件,我需要分为4部分,然后发送数据到数据库;我遇到的问题是CSV文件可能是1GB+(一次可能不止一个),这会造成各种时间延迟和内存问题

我想得到一些关于如何改进和加快流程的帮助

我正在测试的文件有45000条记录~10mb文件

现在我正在将文件加载到数组中,数组使用的大小大约是文件大小的3倍,所以对于10mb文件,我们说的是30mb内存;我希望通过逐行读取文件来减少对30mb内存的需求,但现在来看一下这个

处理部分相当简单,基本上我循环处理数据数组

最后一部分是将数据保存到数据库,目前的主要问题在于,将数据保存到数据库需要花费时间

起初,我尝试创建一个大字符串并将其全部发送到DB中,但22k记录需要大约2GB的ram内存;即使这个过程很快,我的内存还是会一直不足

我目前实现的方法是一次添加行,这不需要太多内存,但处理45k条记录可能需要将近一个小时

我的下一步是创建一个包含完整查询列表的mysql文件,并通过mysql导入功能将所有查询导入mysql

如果有人能建议我如何进一步提高脚本的性能,那就太好了


更新1 现在我不再将文件加载到内存中,而是逐行处理文件。处理一个大文件不需要很长时间。处理500MB的数据文件需要几秒钟

在导入DB方面,我尝试了两种方法:

  • 使用PDO,一次导入语句:处理5MB数据文件大约需要1分钟;很慢
  • 使用mysql 目前我正在考虑尝试“加载数据填充”,但由于有两个表具有一对多关系,并且我需要有最后一个插入的id,所以我需要做一些变通


    更新2

    加载数据本地填充管理解决了一些硬盘问题;我还必须使用SplFileObject使文件读取对我来说更容易。我为LoadDataLocalInfle创建的文件仍然很大,但比以前好多了

    目前,我必须在文件中执行循环,并存储信息所在位置的起点/终点,在执行此操作时,我创建了所有表,但需要外键的表除外。所以我所做的是:

    表A和表B具有一对多关系:表A在第一个循环(通过文件的循环)处创建,此外,我们将表B的参数存储在表A中的单元格中

    在第二个循环中,我们循环表A,从单元格中获取数据,并在表B中创建一组新行

    在第一个循环中,我必须解析表B的参数,以提高第二个循环的性能

    我在第二个循环中有很多foreach/for语句,因为第二个循环需要花费x4的时间才能完成

    10MB文件当前性能如下:

    • 第一圈6秒
    • 第二圈12秒
    • 平均总时间18-20秒
    但是,随着文件变大,性能似乎会恶化,40MB文件:

    • 第一圈30秒
    • 第二圈60秒
    • 平均总时间90-100秒
    如果我不在第一个循环中为10MB的表B性能解析参数:

    • 第一圈3秒
    • 第二圈16秒
    • 平均总时间19-22秒
    40MB文件的性能在第一个循环中非常好,但在第二个循环中非常糟糕

    在第一个和第二个循环中没有任何foreach循环,处理10MB的数据大约需要3-4秒

    第一个循环中组织表B参数的foreach循环示例:

    public function parseRawParam($line, $titles) {
            $params = [];
    
            $line = str_replace("\n", "", $line);
            $rows = explode(",", $line);
    
            for($row_i = 4; $row_i < count($rows); $row_i++) {
                if(strlen(trim($rows[$row_i])) < 1) {
                    break;
                }
    
                $params[$titles[$row_i]] = $rows[$row_i];
            }
    
            return $params;
        }
    

    我一直在研究不同PHP版本之间的性能,PHP7比PHP5.6快得多,因此我希望升级PHP版本并提高性能。

    对于需要使用LOAD DATA INFILE的数据库。如果要对CSV数据进行任何数据更改,您应该能够构建一个包含行的文本文件,以便一次性批量插入到数据库表中。这将减少单表行插入的锁定,因为这样做成本很高


    研究加载数据填充以将其分块…?这是一种时空权衡。你有多少空间或者你愿意牺牲多少时间。每个查询1行→ 非常慢,每个查询22k行→ 速度快,但内存需求巨大。最优解→ 我遇到的问题是,文件中有五个不同表的数据;其中两个有一对多的关系,我需要使用最后一个插入的ID,你不是要求它在一次点击中做太多。在进行其他插入时,是否可以将问题分解。ID的集合被收集在一个SELECT中,然后存储在一个数组中,并根据该数组进行查找,而不是针对每个ID查找数据库?如果出现故障,总会有一个更简单的解决方案。目前我正在考虑的一个解决方案是使用触发器。有关表格包括:记录和参数;1记录可能有许多参数。计划是在“记录”表中添加额外的列,用于存储参数;当插入行时,将触发如何从单元格中获取“参数”,并将新行插入“参数”表中。另一个解决方案是循环数据两次,非常简单
    public function insertParam($record_id, $params) { 
            $sql = "";
            foreach ($params as $param => $value) {  
                $sql  = '"' . $record_id . '","' . str_replace("'", "\'", trim($param)) . '","' . trim($value) . '";';
            }
            return $sql; 
        }