Как ускорить разбор XML файла?
Необходимо прочитать и разобрать структуру больших фалов XML. Понял что где-то есть проблема в производительности, но не могу понять где именно и как исправить. Когда запускаю скрипт, то ни процессор ни HDD практически не задействуются. HDD практически нулевая загрузка, память тоже не отъедается и не заканчивается. Получается скрипт работает не на полную мощность ресурсов ПК. Для примера файл размером 1.01Gb с 3 876 111 строк, обрабатывается за 85с на моей конфигурации(i5-6500, RAM 16GB,HDD 2Tb,PHP 8.3.2)
<?php
$log= 'D:\web\test\Apache24\htdocs\multiLoadXML\log_xml_load_gar.log';
$full_dir='D:\gar\gar_xml\23\AS_HOUSES_20240418_13ca2188-7aa9-461c-bee8-e770d7eda013.XML';
$start = microtime(true);
if($fp=fopen($log,'w+')){
fwrite($fp,"Запись начата в - ".date("d-m-Y h:i:s")."\r\n");
fclose($fp);
}
$origin_filds=array(
'ID'=>null,
'OBJECTID'=>null,
'OBJECTGUID'=>null,
'CHANGEID'=>null,
'HOUSENUM'=>null,
'ADDNUM1'=>null,
'ADDNUM2'=>null,
'HOUSETYPE'=>null,
'ADDTYPE1'=>null,
'ADDTYPE2'=>null,
'OPERTYPEID'=>null,
'PREVID'=>null,
'NEXTID'=>null,
'UPDATEDATE'=>null,
'STARTDATE'=>null,
'ENDDATE'=>null,
'ISACTUAL'=>null,
'ISACTIVE'=>null
);
$teg='HOUSE';
$ins_rows=0;
$z = new XMLReader;
$z->open($full_dir);
$doc = new DOMDocument;
$z->read();
while ($z->read()&&$z->name==$teg)
{
$node = simplexml_import_dom($doc->importNode($z->expand(), true));
$atts_object = $node->attributes();
$atts_array = (array) $atts_object;
$atts_array = $atts_array['@attributes'];
$temp_arr=array_merge($origin_filds,$atts_array);
$ins_rows++;
}
$z->close();
$time = microtime(true) - $start;
echo 'Строк: '.$ins_rows."\r\n";
echo $time.' сек.'."\r\n";
if($fp=fopen($log,'a')){
fwrite($fp,$time.' сек.'."\r\n");
fwrite($fp,'Обработано '.$ins_rows." строк \r\n");
fclose($fp);
}
Вывод:
Строк: 3876111
85.836812019348 сек.
Ответы (1 шт):
Возможно есть способ ещё ускорить процесс парсинга XML(может настройками самого PHP, тюнинг php.ini), но на данный момент самый быстрый способ найденный мной использование XMLReader без использования dom:
$start = microtime(true);
$reader = new XMLReader();
if (!$reader->open('D:\gar\gar_xml\23\AS_HOUSES_20240418_13ca2188-7aa9-461c-bee8-e770d7eda013.XML')) {
die("Failed to open '*.xml'");
}
$origin_filds=array(
'ID'=>null,
'OBJECTID'=>null,
'OBJECTGUID'=>null,
'CHANGEID'=>null,
'HOUSENUM'=>null,
'ADDNUM1'=>null,
'ADDNUM2'=>null,
'HOUSETYPE'=>null,
'ADDTYPE1'=>null,
'ADDTYPE2'=>null,
'OPERTYPEID'=>null,
'PREVID'=>null,
'NEXTID'=>null,
'UPDATEDATE'=>null,
'STARTDATE'=>null,
'ENDDATE'=>null,
'ISACTUAL'=>null,
'ISACTIVE'=>null
);
$row=0;
while($reader->read()) {
if ($reader->nodeType == XMLReader::ELEMENT && $reader->name == 'HOUSE') {
foreach($origin_filds as $key => $value){
$temp_arr[$key] = $reader->getAttribute($key);
}
}
$row++;
}
$time = microtime(true) - $start;
echo $time.' сек.'."\r\n";
echo 'Строк: '.$row."\r\n";
$reader->close();
php 8.3.8 + сброс настроек php.ini по умолчанию + выше написанный код сократили время вдвое. Теперь скрипт парсит этот же файл за 30с
...\php-8.3.8\php.exe .\testReadXML.php
Строк: 3876111
30.55620098114 сек.