Была задача сделать сверку 2 файлов в каждом по 1 млн. строк. Сверка на уровне базы занимала оочень продолжительное время, примерно сутки и более.
Как и сколько времени это займет на PHP если делать это в памяти через массивы?
Разбираемся.
Изначальный элемент 1 массива (один элемент для примера)
[0]=> string(128) «183dc1b67dbce515fa91;183dc1b67dbce515fa91;183dc1b67dbce515fa91;183dc1b67dbce515fa91;183dc1b67dbce515fa91;183dc1b67dbce515fa91;1»
Изначальный элемент 2 массива (один элемент для примера)
[0]=> string(128) «183dc1b67dbce515fa91;183dc1b67dbce515fa91;183dc1b67dbce515fa91;183dc1b67dbce515fa91;183dc1b67dbce515fa91;183dc1b67dbce515fa91;1»
Далее используем функцию array_flip – она возвращает массив наоборот, то есть ключи массива становятся значениями, а значения массива становятся ключами
И тогда:
Измененный элемент 1 массива станет таким
[«183dc1b67dbce515fa91;183dc1b67dbce515fa91;183dc1b67dbce515fa91;183dc1b67dbce515fa91;183dc1b67dbce515fa91;183dc1b67dbce515fa91;1»]=> int(0)
Измененный элемент 2 массива станет таким
[«183dc1b67dbce515fa91;183dc1b67dbce515fa91;183dc1b67dbce515fa91;183dc1b67dbce515fa91;183dc1b67dbce515fa91;183dc1b67dbce515fa91;1»]=> int(0)
Смысл этого в том, что далее мы будем сравнивать элементы не по значению элемента, а по ключам(это даст нам возможность схлопнуть массивы по одинаковым значениям ключей), которые сейчас у нас содержат значения элементов.
Далее запускаем скрипт и получаем строки из 2 файла, которых нет в 1 файле и записываем в результирующий файл
dima@Ubuntu:~/PHP/array_compare$ time php -d memory_limit=4G ./compare.php
Время выполнения скрипта у меня (но у меня стоит PHP7.2 )составило 12 секунд
Памяти мы потребили на момент выполнения 400 мб
Memory Consumption is 0.37 MB
Memory Consumption is 401.56 MB
real 0m12,664s
user 0m4,008s
sys 0m8,600s
Сам скрипт довольно простой, благодаря готовым функциям PHP и сейчас сам скрипт вот
//читаем 1 файл в массив
$a = file(«random_1.csv»);
//читаем 2 файл в массив
$b = file(«random_2.csv»);
//соритруем массивы
sort($a, SORT_STRING);
sort($b, SORT_STRING);
//функция для вычисления расхождений 1 массива от 2 массива
function large_array_diff($b, $a){
// меняем наборот в 1 массиве ключ и значение
$at = array_flip($a);
// меняем наборот во 2 массиве ключ и значение
$bt = array_flip($b);
//вычисляем расхождение массивов сравнивая ключи
$d = array_diff_key($bt, $at);
//возвращаем в функции массив-результат сравнения ключей
return array_keys($d);
}
//выполянем функцию подставляя массивы в качестве аргументов
$diff = large_array_diff($b, $a);
//пишем результат сравнения в файл
file_put_contents(‘compare_diff.csv’, $diff, FILE_APPEND);
Тест на PHP5.6 – более медленный чем 7 версия и больше жрет памяти.
Строки получились более длинными вот так например
0bff640c25f2b16720249d6e5bda91a9;0bff640c25f2b16720249d6e5bda91a9;0bff640c25f2b16720249d6e5bda91a9;0bff640c25f2b16720249d6e5bda91a9;0bff640c25f2b16720249d6e5bda91a9;0bff640c25f2b16720249d6e5bda91a9;1
Результат сравнения двух файлов с 1 млн строк
- времени работали 8 секунд
- памяти пожрали 1Гб
- в результирующий файл попало 1 млн строк (т.е разница между файлами 100%) Проверил потом diff – показал разницу всех строк
[ium@0400hpium03 array_compare]$ diff random_1.csv random_2.csv | wc -l
2000002 - проверял на файлах с меньшим количеством строк, чтобы смотреть разницу – скрипт работает правильно, т.е ошибок нет при сравнении строк находит только разные.
[tnm@0400hp]$ time php -d memory_limit=4G ./compare.php
Memory Consumption is 0.22 MB
Memory Consumption is 1054.2 MB
real 0m8.286s
user 0m5.263s
sys 0m2.812s