@microf

Как загрузить большой XML?

Добрый день. Есть много организаций с почтовыми адресами, которые оказывают услуги.
Имеем XML файл в 13 000 000 строчек и весом в 1.2 GB
<companies_list>
	<company>
		<name>ООО "Солнышко"</name>
		<type>Партнер<type>
                <inn>775634541</inn>
                <addresses_list>
                    <address>
                        <city>Москва</city>
                        <street>Солнечная улица, 5</street>
                        <services_list>
                           <service>Услуга 1</service>
                           <service>Услуга 2</service>
                          <service>Услуга 3</service>
                        </services_list>
                   </address>
                    <address>
                        <city>Нягань</city>
                        <street>Лунная улица, 5</street>
                        <services_list>
                           <service>Услуга 1</service>
                           <service>Услуга 5</service>
                          <service>Услуга 3</service>
                        </services_list>
                   </address>
                </addresses_list>
          <ogrn>5235452345235</ogrn>
          <date>01.08.2017</date>
       </company>
</companies_list>


Мне необходимо загнать это в базу, вида
'id','inn','ogrn','name','type','city','street' и, соответственно, вторая таблица, связанной с первой, с помощью key_id
'key_id','service'
Вариант 1
while ($reader->read()) {
                        if ($reader->nodeType == XMLReader::ELEMENT && XMLReader::ELEMENT !== 'companies_list') {
                            if ($reader->localName == 'company') {
                                $node = simplexml_import_dom($doc->importNode($reader->expand(), true));
                                try {
                                    $id = ID::next()->getId();
                                    $inn = (string)$node->inn;
                                    $ogrn = (string)$node->ogrn;
                                    $type = (string)$node->type;
                                    $date = (string)$node->date;
                                    
                                        foreach ($node->addresses_list->address as $address_list) {                                        
                                            $city = (string)$address_list->city;
                                            $street = (string)$address_list->street;
                                            $address_service = [];
                                            foreach ($address_list->services->service as $service) {
                                                $address_service[] = $service;
                                            }
                                            $insertQuery->execute([
                                                ':id' => $id,
                                                ':inn' => $inn,
                                                ':ogrn' => $ogrn,
                                                ':type' => $type,
                                                ':name' => $name,                                                
                                                ':date' => $date,                                                
                                                ':city' => $city,
                                                ':street' => $street                                                
                                            ]);
                                            foreach ($address_service as $row) {
                                                $insertQueryWorks->execute([
                                                    ':key_id' => $id,
                                                    ':service' => $row
                                                ]);
                                            }

                                        }
                                    }

В этом варианте скрипт работает, но порядка 23 часов. При этом (тут уже вопрос больше про mySql), непонятно, что сделать первичным или уникальным ключом. Скрипт отрабатывает положенные 300 000 компаний и не останавливается, а дальше продолжает работать. Второй минус - если я делаю запись в базу во внутреннем цикле - я не получу значение поля date - на тот момент оно недостижимо.
Вариант 2
Воспользоваться LOAD XML
Его я еще не пробовал, ибо не могу сообразить, как один файл разбить на несколько таблиц. Когда то я делал с большим csv, как это сделать с xml, неясно
Кто что посоветует для загрузки большого XML?
  • Вопрос задан
  • 217 просмотров
Пригласить эксперта
Ответы на вопрос 2
NeiroNx
@NeiroNx
Программист
Бльшие XML не надо пытаться обработаь как DOM целиком - не влезет. Вы еще базу ФИАС не видели там один файл 7 гиг.

Попробуйте читать постепенно и выковыривать <company></company>
Ответ написан
firedragon
@firedragon
Не джун-мидл-сеньор, а трус-балбес-бывалый.
Я бы сделал так:
1. 1 проход заполнение словаря сервисов в памяти, причем первичный ключ сами гененируете
2. удаление индексов из таблицы сервисов и пакетная вставка сервисов
3. Восстановление индексов и identity
4. Снятие индексов с базы организаций
5. Пакетная вставка организаций по ~ 10 000 за раз.
6. Восстановление индексов, identity , ограничений и внешних ключей

Причем все это лучше делать на соседней базе, а потом менять их местами.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы