Как ускорить разбор 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 шт):

Автор решения: Ivan Chuzhmakov

Возможно есть способ ещё ускорить процесс парсинга 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 сек.
→ Ссылка