Провёл небольшое исследование заливки массива в базу.
Массив формируется 20 сек и содержит 1,2 млн строк.
В самом начале, когда всё плохо, за 1 час из массива в базу записалось 50 тыс. записей.
Далее сделал некоторые улучшения. Слева - время заливки всего массива, правее - что сделано.
4 мин 07 сек - завернул процесс в транзакцию beginTransaction() - commit()
3 мин 58 сек - +временно отключил индексы ALTER TABLE table1 DISABLE KEYS
2 мин 49 сек - +вместо bindParam использовал сцепление для формирования VALUES, каждая строка отдельно.
Далее начал формировать тем же способом VALUES для различного количества строк.
10 мин 44 сек - 10 тыс. строк
3 мин 45 сек - 5 тыс. строк
2 мин 38 сек - 3 тыс. строк
2 мин 04 сек - 2 тыс. строк
1 мин 22 сек - 1 тыс. строк
1 мин 12 сек - 500 строк
1 мин 07 сек - 200 строк
1 мин 06 сек - 150 строк
1 мин 00 сек - 100 строк
1 мин 08 сек - 80 строк
1 мин 10 сек - 50 строк
График типа параболы ветвями вверх, имеется точка минимума.
Выводы:
1) наибольшее быстродействие в моём частном случае достигается при загрузке массива порциями примерно по 100 строк (можно ещё уточнить).
2) время формирования VALUES в зависимости от количества записей растёт нелинейно. Начиная с нескольких десятков тысяч строк время формирования превышает (и значительно) время заливки соответствующей порции. 50 тыс. я еле дождался, а на 100 тыс. превысило разумные пределы.
Я думал, что в 3-м варианте {} сильно замедляют по сравнению с конкатенцией во 2-м.
Ещё я думал, что VALUES в запросе можно написать пару-тройку штук, а оказывается их общая длина ограничена только переменной max_allowed_packet.
На LOAD DATA INFILE я вышел с этой страницы phpclub.ru/mysql/doc/insert-speed.html
"Вариант 2: заключить все вставки в транзакцию"
Между beginTransaction() и commit()?
У меня в настройках сейчас длина запроса может быть до max_allowed_packet= 32M.
В эти 32М можно запихнуть 300 тыс. VALUES по 100 символов и закачать всю базу за 4 запроса.
Очень перспективно.
Пишут, что с помощью LOAD DATA INFILE из текстового файла это можно сделать ещё быстрее примерно на 30-40%.
Будем проверять.
Руслан Федосеев,
Увеличивал max_execution_time.
Дошёл до 3600 сек.
За 1 час записывается около 50 тыс. записей, а их в массиве пока что около 1,2 млн и есть тенденция к увеличению.
Причём массив формируется за 20 сек.
Вся оперативная память сейчас используется впритык.
Поэтому хочу исключить формирование массива из техпроцесса, а как, если простое переписывание может занять сутки.
Операция выполняется по запросу, типа отчёт.
Статья интересная, но в ней есть момент:
"... foreach увеличивает указатель массива до начала кода пользователя, а не после. Так что, даже если код все еще работает с первым элементом, foreach уже переместил указатель ко второму."
Но так он тоже не обманывается:
$m[]=0;
$m[]=1;
foreach ($m as $key=>$value){
$m[]=$value+2;
};
Раз foreach работает с копией, то буду искать другой способ.
Дмитрий,
Пусть остались записи с номерами 17, 20,21. а 18 и 19 удалены
$id = 17;
Попадаю на запись #20
$id++;
т.е. $id = 18, снова попадаю на запись #20
$id++;
т.е. $id = 19, и опять на неё же.
Не анализировать же каждый раз.
Я правильно рассуждаю?
Дмитрий, Хотел возразить, типа у меня просмотр должен быть в несколько другом порядке, но понял :), что это дела не меняет, главное всё просмотреть по неубыванию второго поля. Годится. Спасибо.
Дмитрий,
Это меня и смущает, почему не работает.
Процитирую Вас:
"доступна только внутри самой функции"
Если в функции f1 вызывается другая функция f2, то разве f2 не внутри функции f1?
Если на самом верхнем уровне вызывается функция f2, то она внутренняя и можно писать global.
Это же почти полная аналогия.