0

好的,所以我有一个按钮。按下时它会这样做:

Javascript

$("#csv_dedupe").live("click", function(e) {
    file_name = 'C:\\server\\xampp\\htdocs\\Gene\\IMEXporter\\include\\files\\' + $("#IMEXp_import_var-uploadFile-file").val();
    $.post($_CFG_PROCESSORFILE, {"task": "csv_dupe", "file_name": file_name}, function(data) {
        alert(data);
    }, "json")
});

这个 ajax 调用被发送到这个:

PHP

class ColumnCompare {
    function __construct($column) {
        $this->column = $column;
    }

    function compare($a, $b) {
        if ($a[$this->column] == $b[$this->column]) {
            return 0;
        }
        return ($a[$this->column] < $b[$this->column]) ? -1 : 1;
    }
}

if ($task == "csv_dupe") {
    $file_name = $_REQUEST["file_name"];

    // Hard-coded input
    $array_var = array();
    $sort_by_col = 9999;
    //Open csv file and dump contents
    if(($handler = fopen($file_name, "r")) !== FALSE) {
        while(($csv_handler = fgetcsv($handler, 0, ",")) !== FALSE) {
            $array_var[] = $csv_handler;
        }
    }
    fclose($handler);

    //copy original csv data array to be compared later
    $array_var2 = $array_var;

    //Find email column
    $new = array();
    $new = $array_var[0];
    $findme = 'email';
    $counter = 0;
    foreach($new as $key) {
        $pos = strpos($key, $findme);
        if($pos === false) {
            $counter++;
        }
        else {
            $sort_by_col = $counter;
        }
    }
    if($sort_by_col === 999) {
        echo 'COULD NOT FIND EMAIL COLUMN';
        return;
    }

    //Temporarily remove headers from array
    $headers = array_shift($array_var);
    // Create object for sorting by a particular column
    $obj = new ColumnCompare($sort_by_col);
    usort($array_var, array($obj, 'compare'));

    // Remove Duplicates from a coulmn
    array_unshift($array_var, $headers);
    $newArr = array();
    foreach ($array_var as $val) {
        $newArr[$val[$sort_by_col]] = $val;
    }
    $array_var = array_values($newArr);

    //Write CSV to standard output
    $sout = fopen($file_name, 'w');
    foreach ($array_var as $fields) {
        fputcsv($sout, $fields);
    }
    fclose($sout);

    //How many dupes were there?
    $number = count($array_var2) - count($array_var);    
    echo json_encode($number);
}

这个 php 从 csv 文件中获取所有数据。列和行,并使用 fgetcsv 函数将所有数据分配给一个数组。现在我在那里有代码,它还通过单个列对 csv 文件进行重复数据删除(查找并删除副本的副本)。保持整个数组的行列结构不变。

唯一的问题是,即使它适用于我测试过的有 10 行左右的小文件,它也不适用于 25,000 行的文件。

现在在你说它之前,我已经进入了我的 php.ini 文件并将 max_input、文件大小、最大运行时间等更改为天文值,以确保 php 可以接受高达 999999999999999MB 的文件大小和运行几个脚本的时间一百年。

我使用了一个包含 25,000 条记录的文件并执行了脚本。两个小时过去了,fiddler 仍然显示尚未发回 http 请求。有人可以给我一些优化服务器和代码的方法吗?

我能够使用来自帮助我解决另一个问题的用户的代码,我最初发布了如何做到这一点。我现在担心的是,即使我对其进行了测试,但我想知道如何在不到一分钟的时间内使其工作。Excel 可以在几秒钟内对一列一百万条记录进行重复数据删除 为什么 php 不能这样做?

4

1 回答 1

0

Sophie,我假设您在编写此类应用程序方面没有经验,因为 IMO 这不是解决此问题的方法。所以我会相应地推销这个。

当您遇到这样的性能问题时,您确实需要对问题进行二进制切分以了解发生了什么。所以第 1 步是将 PHP 计时问题与 AJAX 分离,并简单了解您的方法为何如此迟钝。使用本地安装的 PHP-cgi 执行此操作,甚至使用您的 Web 安装并发出标头('Context-Type: text/plain')并转储每个步骤的微定时。读取 CSV 需要多长时间,同上排序,然后是 nodup,然后是写入?对一系列 CSV 文件大小执行此操作,每次行数增加 10 倍。

还要在每个步骤中执行 memory_get_usage() 以查看您是如何占用内存的。因为你的方法是一个真正的猪,你可能会因为达到配置的内存限制而出错——一个 phpinfo() 会告诉你这些。

读取、nodup 和写入都是 o(N),但排序最多为 o(NlogN),最坏为 o(N 2 )。您的排序也每次比较调用一个 PHP 方法,所以会很

我不明白你为什么要进行排序,因为你的 nodup 算法没有利用行已排序的事实。

(顺便说一句,排序也会对标题行进行内联排序,所以如果你仍然想这样做,你需要在排序之前取消它。)

您还需要考虑其他问题,例如

  • 使用原始参数作为文件名会使您容易受到攻击。最好修复相对于 DOCROOT/Gene/IMEXporter/include 的补丁,并对文件名强制执行一些语法。

  • 您需要考虑读取和重写大文件的原子性作为对 Web 请求的响应——如果两个客户端同时发出请求会发生什么。

  • 最后,您将其与 Excel 进行比较,加载和保存 Excel 文件可能需要时间,而且 Excel 不必扩展以同时响应 10 或 100 或用户。在事务系统中,您通常使用 D/B 后端来处理此类事情,如果您使用 Web 界面来计算繁重的任务,您需要接受 Apache(或等效的服务器)硬内存和时间限制并砍掉您的算法和相应的方法。

于 2012-07-30T21:00:59.440 回答