【问题标题】:How to optimize loops for large CSV files data extraction如何优化大型 CSV 文件数据提取的循环
【发布时间】:2018-10-30 03:22:32
【问题描述】:

我有一个关于代码优化的问题。 十多年来,除了简单的循环,我没有编写任何代码。

我创建了下面的代码,它运行良好,但对于我的需求来说速度非常慢。

本质上,我有 2 个 CSV 文件:

  • 一个包含大约 500 000 条记录的源 CSV 文件,例如:att1、att2、source_id、att3、att4(实际上大约有 40 列)
  • 一个包含大约 1.2 亿条记录的主 CSV 文件,例如:att1、att2、att3、main_id、att4(实际上大约有 120 列)

对于源文件中的每个 source_id,我的代码都会在主文件中解析 main_id == source_id 的所有行,并将这些行中的每一行写入一个新文件中。

你对我如何优化代码有什么建议吗?

<?php

$mf = "main.csv";
$mf_max_line_length = "512";
$mf_id = "main_id";

$sf = "source.csv";
$sf_max_line_length = "884167";
$sf_id = "source_id";


if (($mf_handle = fopen($mf, "r")) !== FALSE)
{
    // Read the first line of the main CSV file
    // and look for the position of main_id
    $mf_data = fgetcsv($mf_handle, $mf_max_line_length, ",");
    $mf_id_pos = array_search ($mf_id, $mf_data);

    // Create a new main CSV file
    if (($nmf_handle = fopen("new_main.csv", "x")) !== FALSE)
    {
        fputcsv($nmf_handle,$mf_data);
    } else {
        echo "Cannot create file: new_main.csv" . $sf;
        break;
    }
}

// Open the source CSV file
if (($sf_handle = fopen($sf, "r")) !== FALSE)
{
    // Read the first line of the source CSV file
    // and look for the position of source_id
    $sf_data = fgetcsv($sf_handle, $sf_max_line_length, ",");
    $sf_id_pos = array_search ($sf_id, $sf_data);

    // Go trhough the whole source CSV file
    while (($sf_data = fgetcsv($sf_handle, $sf_max_line_length, ",")) !== FALSE)
    {
        // Open the main CSV file
        if (($mf_handle = fopen($mf, "r")) !== FALSE)
        {
            // Go trhough the whole main CSV file
            while (($mf_data = fgetcsv($mf_handle, $mf_max_line_length, ",")) !== FALSE)
            {
                // If the source_id matches the main_id
                // then we write it into the new_main CSV file
                if ($mf_data[$mf_id_pos] == $sf_data[$sf_id_pos])
                {
                    fputcsv($nmf_handle,$mf_data);
                }
            }
            fclose($mf_handle);
        }
    }
    fclose($sf_handle);
    fclose($nmf_handle);
}

?>

【问题讨论】:

  • 您的问题是您正在使用嵌套循环来查找您的连接。基本上,对于源文件中的每一行,您将遍历整个主文件。这意味着您最终将获得 60 万亿(500,000 * 120,000,000)次读取,而不是 1.205 亿(500,000 + 120,000,000)次读取。尝试在一个循环中将主文件的结果缓存到一个数组中,并以您正在搜索的索引的值为键。然后另一个循环可以使用简单的isset 检查该数组。
  • 谢谢,我害怕加载 500 000 行(大约 1Gb 的数据)和 1.2 亿行(大约 25Gb)来炸毁我的笔记本电脑,但我可以设置一个有足够内存来处理的 VM它。

标签: php file loops csv


【解决方案1】:

听起来像是 mysql 的工作。

首先,您需要根据所有字段创建表格。 See here

然后,您将加载数据。 See here

最后,您将创建如下查询:

SELECT * INTO OUTFILE '/tmp/something.csv' 
    FIELDS TERMINATED BY ',' ENCLOSED BY '"' 
    LINES TERMINATED BY '\n' 
FROM source_table INNER JOIN main_table ON 
    source_table.source_id=main_table.main_id;

【讨论】:

  • 这实际上非常聪明,它将给我更多的灵活性和轻松的操作数据而无需开发。感谢您的建议!
  • 您可以进一步优化 id 列上的索引以及您想要运行 WHERE 语句的任何其他列。查找有关索引的 mysql 文档。就像在 sometable(somefield) 上 CREATE INDEX 'somename';
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-11-08
  • 2018-03-23
  • 2015-02-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多