好的,我有一个按钮。按下它时会这样做:
的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,filesize,max time running等更改为天文值,以确保php可以接受文件大小上升到999999999999999MB并运行其脚本的时间几百年。
我使用了包含25,000条记录的文件并执行该脚本。已经两个小时了,小提琴手仍然显示还没有发回http请求。有人可以给我一些方法,我可以优化我的服务器和我的代码吗?
我能够使用那些帮助我的用户的代码,这个用户在我发布的另一个问题上最初是如何做到的。我现在担心的是,即使我测试了它,我想知道如何让它在不到一分钟的时间内完成。 Excel可以在几秒内重复删除一百万条记录的列,为什么php不能这样做?
答案 0 :(得分:0)
当你遇到这样的性能问题时,你真的需要二进制来解决问题,以了解发生了什么。因此,第1步是将PHP计时问题与AJAX分离,并简单了解为什么您的方法如此反应迟钝。使用本地安装的PHP-cgi执行此操作,甚至使用Web安装并发出标头('Context-Type:text / plain')并转储每个步骤的microtiming。 CSV读取需要多长时间,同样排序,然后是nodup,然后是写入?对于每次行数增加10倍的CSV文件大小,请执行此操作。
还要在每一步执行memory_get_usage()以查看如何扼杀内存。因为你的方法真的很糟糕,并且你可能通过达到配置的内存限制而错误 - phpinfo()会告诉你这些。
read,nodup和write都是o(N),但最好是o(NlogN),最坏的是o(N 2 )。您的排序也是每次比较调用PHP方法,因此慢。
我不明白为什么你甚至在进行排序,因为你的nodup算法没有利用行被排序的事实。
(顺便说一句,排序也会对标题行进行内联排序,所以你需要在之前取消它,如果你还想这样做的话。)
您还需要考虑其他问题,例如
使用原始参数作为文件名会使您容易受到攻击。最好修复相对于DOCROOT / Gene / IMEXporter / include的补丁,并对文件名强制执行一些语法。
您需要考虑读取和重写大文件的原子性,作为对Web请求的响应 - 如果两个客户端同时发出请求,会发生什么。
最后你将它与Excel进行比较,加载和保存Excel文件可能需要一些时间,并且Excel不必按比例缩放以同时响应10s或100s或用户。在事务系统中,您通常使用D / B后端进行此类操作,如果您使用Web界面来计算繁重的任务,则需要接受Apache(或等效服务器)硬内存和时序约束并切断您的algos并采取相应的方法。