Помогите оптимизировать добавление данных

  • Автор темы Автор темы SiZE
  • Дата начала Дата начала

SiZE

Новичок
Помогите оптимизировать добавление данных

Есть задача внести из XML файла данные в MySQL.

Условия: внести все полученные данные, предварительно проверив на уникальность.

XML обрабатываю через PHP, функцией simplexml_load_file(). Далее формирую массив. Получается порядка 100 000 — 300 000 записей для вставки. Раньше данных было мало, порядка 1000 - 3000 записей. И поэтому достаточно было обойти циклом массив. Сделать для каждой записи SELECT COUNT(id)... с условием проверки на уникальность и в зависимости от результат сделать INSERT или UPDATE.

С увеличением количества записей ситуация координально поменялась при такой вставке данных скрипт начинает жрать от 100 метров до гига и выше. А таких файлов несколько тысяч и сервак вообщем не выдерживает нагрузки.

В кратце код такой:
PHP:
<?
$xml = simplexml_load_file (file.xml);
newArr = array ();
foreach ($xml as $v) {
  $newArr['field1'] = $v['field1'];
  $newArr['field2'] = $v['field2'];
  $newArr['field3'] = $v['field3'];
}

foreach ($newArr as $k => $v) {
  $sql = "INSERT INTO table2 SET field1='$v['field1']'";
  $db->exec ($sql);
  $link = $db->insert_id(); // mysql_insert_id();
  $sql = "SELECT COUNT(id), id FROM table1 WHERE field1='$v['field1']' AND field2='$v['field2']' LIMIT 1";
  $res = $db->exec ($sql);
  if ($res) {
    $sql = "INSERT INTO table1 SET field1='$v['field1']', field2='$v['field2']', field3='$v['field3']', field4='$link'";
    $db->exec ($sql);
  } else {
    $sql = "UPDATE table1 SET field3='$v['field3']' WHERE id='$res['id']'";
    $db->exec ($sql);
  }
}
?>

1. Были мысли создать файл CSV и выгрузить данные в базу, тогда я не знаю как проверить на уникальность записи.
2. Или выгрузить в файл CSV и загрузить во временную таблицу, дубликаты удалить а таблицы слить. Но особо пока не представляю, как слить таблицы.
3. Или пройтись по всему массиву выпонить для каждой записи SELECT COUNT(id) ... удалить из массива дубликаты, на лету создать INSERT INTO table VALUES (1,2,3), (4,5,6), (7,8,9),..., n и загрузить. Не знаю как только MySQL отреагирует если количество VALUES будет порядка 100 000 — 300 000.

Мб что то еще?
 
Re: Помогите оптимизировать добавление данных

Во первых откажись от simplexml - он грузит файл целиком в память.
Юзай DOMDocument с Xpath и ранжируй там в селекторах item() - возможно это будет работать быстрее, кто сталкивался - покритикуйте.
Делай массовые вставки - конечно не по 10000 - делай пачками, например по 500.
 
PHP:
$sql = "SELECT COUNT(id), id FROM table WHERE field1='$v['field1']' AND field2='$v['field2']' LIMIT 1";
  $res = $db->exec ($sql);
  if ($res) {

  } else {
    $sql = "UPDATE table SET field1='$v['field1']', field2='$v['field2']' WHERE id='$res['id']'";
    $db->exec ($sql);
  }

в чём сакральный смысл этого кода?
 
1. insert on duplicate key update | insert ignore
2. start tran / commit по несколько тысяч записей.
3. парсить огромные XML'и лучше через SAX.
 
dr-sm
на мой коммент посмотри :-) что он там вообще апдейтит? :-)))
 
zerkms, ну он там код вроде вкратце привел.
так то да, момент загадочный )))
 
Во первых откажись от simplexml - он грузит файл целиком в память.
Юзай DOMDocument с Xpath и ранжируй там в селекторах item() - возможно это будет работать быстрее, кто сталкивался - покритикуйте.
для больших XML-файлов надо использовать XMLReader
все сливать в промежуточную таблицу (желательно без индексов)
удалять дубликаты
мержить с основной тбл
 
в чём сакральный смысл этого кода?
Что бы понять суть действий производимых скриптом. То, что в примере он апдейтит тоже самое, так это только пример, для краткости. Есть другие поля, по которым не сравнивается уникальность записи, но обновляются при UPDATE. Вобщем думаю это не столь важно :)

-~{}~ 24.09.09 15:31:

Добавлю немного информации. Загрузка xml файла, обход XML дерева с созданием необхоимого массива занимает 15 секунд на 170 000 записей, пиковое потребление памяти 8-9 Мб. Для меня это время приемлемо и код минимален.
Загрузка в базу 170 000 записей в формате описанном выше (SELECT ... INSERT) занимает 20-25 минут и скрипт на PHP отжирает 500-1500 Мб памяти.

-~{}~ 24.09.09 15:32:

Ситуация осложнилась. Перед тем, как добавить запись в таблицу, на основании этих данных мне надо сделать запись в другой таблице получить ID и уже только после этого добавить данные :(
 
пиши в файл, в соответствующем формате и потом LOAD DATA INFILE
 
Автор оригинала: zerkms
пиши в файл, в соответствующем формате и потом LOAD DATA INFILE
А как быть с тем, что мне для каждой записи надо получить ID из другой таблицы? :(
 
SiZE
ну а что тут поделаешь? выгребай сразу побольше пачки, через IN(...)
 
Сверху