Предпочтительный метод хранения массивов PHP (json_encode vs serialize)

Мне нужно хранить многомерный ассоциативный массив данных в плоский файл для целей кэширования. Иногда я могу столкнуться с необходимостью конвертировать его в JSON для использования в моем веб-приложении, но в большинстве случаев я буду использовать массив непосредственно в PHP.

Было бы более эффективно хранить массив как JSON или как сериализованный массив PHP в этом текстовом файле? Я посмотрел вокруг, и кажется, что в новейших версиях PHP (5. 3), json_decode на самом деле быстрее, чем unserialize.

В настоящее время я склоняюсь к сохранению массива в формате JSON, так как считаю, что его легче читать человеку, если это необходимо, его можно использовать как на PHP, так и на JavaScript без особых усилий, а из того, что я прочитал, может даже Быстрее декодировать (хотя не уверен насчет кодировки).

Кто-нибудь знает какие-либо подводные камни? У кого-нибудь есть хорошие тесты, чтобы показать преимущества производительности любого метода?

вопрос задан 29.04.2009
KyleFarris
11731 репутация

19 ответов


  • 520 рейтинг

    Зависит от ваших приоритетов.

    Если производительность - ваша абсолютная характеристика вождения, то непременно используйте самую быструю. Просто убедитесь, что у вас есть полное понимание различий, прежде чем сделать выбор

    • В отличие от serialize(), вам нужно добавить дополнительный параметр, чтобы сохранить символы UTF-8 без изменений: json_encode($array, JSON_UNESCAPED_UNICODE) (в противном случае он преобразует символы UTF-8 в escape-последовательности Unicode).
    • JSON не будет иметь памяти о том, каким был исходный класс объекта (они всегда восстанавливаются как экземпляры stdClass).
    • Вы не можете использовать __sleep() и __wakeup() с JSON
    • По умолчанию только открытые свойства сериализуются с помощью JSON. (в PHP>=5.4 вы можете реализовать JsonSerializable , чтобы изменить это поведение).
    • JSON более портативен

    И, возможно, есть еще несколько отличий, о которых я не могу думать в данный момент.

    Простой тест скорости для сравнения двух

    ответ дан Peter Bailey, с репутацией 92248, 29.04.2009
  • 224 рейтинг

    JSON проще и быстрее, чем формат сериализации PHP, и его следует использовать , если только :

    • Вы храните глубоко вложенные массивы: json_decode() : "Эта функция вернет false, если данные в кодировке JSON глубже 127 элементов. "
    • Вы храните объекты, которые должны быть не сериализованы, как правильный класс.
    • Вы взаимодействуете со старыми версиями PHP, которые не поддерживают json_decode
    ответ дан Greg, с репутацией 248407, 29.04.2009
  • 56 рейтинг

    Я написал статью на эту тему: « Кэшировать большой массив: JSON, serialize или var_export? ". В этом посте показано, что сериализация - лучший выбор для маленьких и больших массивов. Для очень больших массивов (& gt; 70 МБ) JSON - лучший выбор.

    ответ дан Taco, с репутацией 617, 7.07.2009
  • 49 рейтинг

    Вас также может заинтересовать https: // github. com / phadej / igbinary - который предоставляет другой «механизм» сериализации для PHP.

    Мои произвольные / произвольные показатели «производительности», используя PHP 5. 3. 5 на 64-битной платформе шоу:

    JSON:

    • JSON, закодированный в 2. 180496931076 секунд
    • JSON, декодированный в 9. 8368630409241 секунд
    • Сериализованный размер "String": 13993

    Родной PHP:

    • PHP сериализован в 2. 9125759601593 секунд
    • PHP несериализован в 6. 4348418712616 секунд
    • сериализованный "String" размер: 20769

    Igbinary:

    • WIN igbinary, сериализованный в 1. 6099879741669 секунд.
    • WIN . 7737920284271 секунд
    • WIN сериализованный "String" Размер: 4467

    Итак, igbinary_serialize () и igbinary_unserialize () быстрее, и они занимают меньше места на диске.

    Я использовал код fillArray (0, 3), как указано выше, но сделал ключи массива более длинными строками.

    igbinary может хранить те же типы данных, что и собственная сериализация PHP (поэтому нет проблем с объектами и т. Д.), И вы можете сказать PHP5. 3 использовать его для обработки сеанса, если вы этого хотите.

    См. Также http: // ilia. WS / файлы / zendcon_2010_hidden_features. pdf - специально слайды 14/15/16

    ответ дан David Goodwin, с репутацией 2414, 27.01.2011
  • 23 рейтинг

    Y только что протестировал сериализованный код и json кодирование и декодирование, плюс размер, который он будет принимать сохраненную строку.

    JSON encoded in 0.067085981369 seconds. Size (1277772)
    PHP serialized in 0.12110209465 seconds. Size (1955548)
    JSON decode in 0.22470498085 seconds
    PHP serialized in 0.211947917938 seconds
    json_encode() was roughly 80.52% faster than serialize()
    unserialize() was roughly 6.02% faster than json_decode()
    JSON string was roughly 53.04% smaller than Serialized string
    

    Мы можем заключить, что JSON кодирует быстрее и приводит к меньшей строке, но unserialize быстрее декодирует строку.

    ответ дан Blunk, с репутацией 239, 10.07.2010
  • 14 рейтинг

    Если вы кэшируете информацию, которую в конечном итоге захотите «включить» на более позднем этапе, вы можете попробовать использовать var_export . Таким образом, вы принимаете удар только в «сериализации», а не в «сериализации».

    ответ дан Jordan S. Jones, с репутацией 11505, 29.04.2009
  • 11 рейтинг

    Я добавил тест для включения производительности десериализации. Вот цифры, которые я получил.

    Serialize
    
    JSON encoded in 2.5738489627838 seconds
    PHP serialized in 5.2861361503601 seconds
    Serialize: json_encode() was roughly 105.38% faster than serialize()
    
    
    Unserialize
    
    JSON decode in 10.915472984314 seconds
    PHP unserialized in 7.6223039627075 seconds
    Unserialize: unserialize() was roughly 43.20% faster than json_decode() 
    

    Таким образом, json, кажется, быстрее для кодирования, но медленнее в декодировании. Так что это может зависеть от вашего приложения и того, что вы ожидаете сделать больше всего.

    ответ дан Jeff Whiting, с репутацией 292, 23.11.2009
  • 8 рейтинг

    Похоже, я буду использовать serialize по двум причинам:

    • Кто-то отметил, что десериализация выполняется быстрее, чем json_decode, и случай «чтения» звучит более вероятно, чем случай «записи».

    • У меня были проблемы с json_encode при наличии строк с недопустимыми символами UTF-8. Когда это происходит, строка оказывается пустой, что приводит к потере информации.

    ответ дан urraka, с репутацией 81, 27.06.2010
  • 7 рейтинг

    Действительно хорошая тема, и после прочтения нескольких ответов я хочу поделиться своими экспериментами на эту тему.

    У меня есть сценарий использования, когда какую-то «огромную» таблицу нужно запрашивать почти каждый раз, когда я общаюсь с базой данных (не спрашиваю почему, просто факт). Система кэширования базы данных не подходит, так как она не будет кэшировать различные запросы, поэтому я думаю о системах кэширования php.

    Я попытался apcu, но это не соответствовало потребностям, память в этом случае недостаточно надежна. Следующим шагом было кеширование в файл с сериализацией.

    Таблица содержит 14355 записей с 18 столбцами, это мои тесты и статистика по чтению сериализованного кэша:

    JSON:

    Как вы все сказали, основное неудобство json_encode/json_decode заключается в том, что он преобразует все в экземпляр StdClass (или объект). Если вам нужно зациклить его, вы, вероятно, будете преобразовывать его в массив, и да, это увеличивает время преобразования.

    среднее время: 780. 2 мс; использование памяти: 41. 5МБ; Размер файла кэша: 3. 8MB

    Msgpack

    @hutch упоминает msgpack . Симпатичный сайт. Давайте попробуем?

    среднее время: 497 мс; использование памяти: 32 МБ; размер файла кэша: 2. 8MB

    Это лучше, но требует нового расширения; Составление иногда боится людей. , ,

    IgBinary

    @ GingerDog упоминает igbinary . Обратите внимание, что я установил igbinary.compact_strings=Off, потому что меня больше интересует производительность чтения, чем размер файла.

    среднее время: 411. 4 мс; использование памяти: 36. 75 МБ; Размер файла кэша: 3. 3MB

    Лучше, чем MSG Pack. Тем не менее, этот тоже требует компиляции.

    serialize/unserialize

    среднее время: 477. 2 мс; использование памяти: 36. 25MB; Размер файла кеша: 5. 9MB

    Чем выше производительность, чем JSON, тем больше массив, тем медленнее json_decode, но вы уже новичок в этом.

    Эти внешние расширения сужают размер файла и кажутся великолепными на бумаге. Числа не лгут *. Какой смысл компилировать расширение, если вы получаете почти те же результаты, что и при использовании стандартной функции PHP?

    Мы также можем сделать вывод, что в зависимости от ваших потребностей вы выберете что-то другое, чем кто-либо другой:

    • IgBinary действительно хорош и работает лучше, чем MsgPack
    • Msgpack лучше сжимает ваши данные (обратите внимание, что я не пробовал igbinary компактный. опция строки).
    • Не хотите скомпилировать? Используйте стандарты.

    Вот и все, еще одно сравнение методов сериализации, чтобы помочь вам выбрать один!

    * Протестировано с PHPUnit 3. 7. 31, php 5. 5. 10 - только декодирование со стандартным жестким диском и старым двухъядерным ЦП - средние числа в 10 тестах с одинаковыми вариантами использования, ваша статистика может быть другой

    ответ дан soyuka, с репутацией 6068, 17.04.2014
  • 6 рейтинг

    Я очень тщательно протестировал это на довольно сложном, слегка вложенном мультихэше со всеми видами данных в нем (строка, NULL, целые числа), и сериализация / десериализация закончилась намного быстрее, чем json_encode / json_decode.

    Единственное преимущество, которое json имел в моих тестах, это меньший «упакованный» размер.

    Это сделано в PHP 5. 3. 3, дайте мне знать, если вы хотите больше деталей.

    Вот результаты тестов, а затем код для их создания. Я не могу предоставить тестовые данные, так как они раскрывают информацию, которую я не могу выпустить в дикую природу.

    JSON encoded in 2.23700618744 seconds
    PHP serialized in 1.3434419632 seconds
    JSON decoded in 4.0405561924 seconds
    PHP unserialized in 1.39393305779 seconds
    
    serialized size : 14549
    json_encode size : 11520
    serialize() was roughly 66.51% faster than json_encode()
    unserialize() was roughly 189.87% faster than json_decode()
    json_encode() string was roughly 26.29% smaller than serialize()
    
    //  Time json encoding
    $start = microtime( true );
    for($i = 0; $i < 10000; $i++) {
        json_encode( $test );
    }
    $jsonTime = microtime( true ) - $start;
    echo "JSON encoded in $jsonTime seconds
    "; // Time serialization $start = microtime( true ); for($i = 0; $i < 10000; $i++) { serialize( $test ); } $serializeTime = microtime( true ) - $start; echo "PHP serialized in $serializeTime seconds
    "; // Time json decoding $test2 = json_encode( $test ); $start = microtime( true ); for($i = 0; $i < 10000; $i++) { json_decode( $test2 ); } $jsonDecodeTime = microtime( true ) - $start; echo "JSON decoded in $jsonDecodeTime seconds
    "; // Time deserialization $test2 = serialize( $test ); $start = microtime( true ); for($i = 0; $i < 10000; $i++) { unserialize( $test2 ); } $unserializeTime = microtime( true ) - $start; echo "PHP unserialized in $unserializeTime seconds
    "; $jsonSize = strlen(json_encode( $test )); $phpSize = strlen(serialize( $test )); echo "
    serialized size : " . strlen(serialize( $test )) . "
    "; echo "json_encode size : " . strlen(json_encode( $test )) . "


    "; // Compare them if ( $jsonTime < $serializeTime ) { echo "json_encode() was roughly " . number_format( ($serializeTime / $jsonTime - 1 ) * 100, 2 ) . "% faster than serialize()"; } else if ( $serializeTime < $jsonTime ) { echo "serialize() was roughly " . number_format( ($jsonTime / $serializeTime - 1 ) * 100, 2 ) . "% faster than json_encode()"; } else { echo 'Unpossible!'; } echo '
    '; // Compare them if ( $jsonDecodeTime < $unserializeTime ) { echo "json_decode() was roughly " . number_format( ($unserializeTime / $jsonDecodeTime - 1 ) * 100, 2 ) . "% faster than unserialize()"; } else if ( $unserializeTime < $jsonDecodeTime ) { echo "unserialize() was roughly " . number_format( ($jsonDecodeTime / $unserializeTime - 1 ) * 100, 2 ) . "% faster than json_decode()"; } else { echo 'Unpossible!'; } echo '
    '; // Compare them if ( $jsonSize < $phpSize ) { echo "json_encode() string was roughly " . number_format( ($phpSize / $jsonSize - 1 ) * 100, 2 ) . "% smaller than serialize()"; } else if ( $phpSize < $jsonSize ) { echo "serialize() string was roughly " . number_format( ($jsonSize / $phpSize - 1 ) * 100, 2 ) . "% smaller than json_encode()"; } else { echo 'Unpossible!'; }
    ответ дан Mr. Sox, с репутацией 61, 17.11.2010
  • 5 рейтинг

    Я также сделал небольшой тест. Мои результаты были одинаковыми. Но мне нужно производительность декодирования. Там, где я заметил, как говорили несколько человек выше, unserialize быстрее, чем json_decode. unserialize занимает примерно 60-70% времени json_decode. Итак, вывод довольно прост: Когда вам нужна производительность в кодировании, используйте json_encode, когда вам нужна производительность при декодировании, используйте unserialize. Поскольку вы не можете объединить две функции, вы должны сделать выбор, где вам нужно больше производительности.

    Мой тест в псевдо:

    • Определите массив $ arr с несколькими случайными ключами и значениями
    • для x & lt; 100; х ++; сериализовать и json_encode массива и $ arr
    • для y & lt; 1000; у ++; json_decode строка в кодировке json - время расчета
    • для y & lt; 1000; у ++; десериализовать сериализованную строку - время расчета
    • повторить результат, который был быстрее

    В среднем: unserialize выиграл в 96 раз больше, чем в 4 раза больше кода json_decode. В среднем примерно 1. 5 мс над 2. 5мс.

    ответ дан Jelmer, с репутацией 2239, 12.11.2012
  • 2 рейтинг

    Прежде чем принять окончательное решение, имейте в виду, что формат JSON небезопасен для ассоциативных массивов - json_decode() будет возвращать их в виде объектов:

    $config = array(
        'Frodo'   => 'hobbit',
        'Gimli'   => 'dwarf',
        'Gandalf' => 'wizard',
        );
    print_r($config);
    print_r(json_decode(json_encode($config)));
    

    Выход:

    Array
    (
        [Frodo] => hobbit
        [Gimli] => dwarf
        [Gandalf] => wizard
    )
    stdClass Object
    (
        [Frodo] => hobbit
        [Gimli] => dwarf
        [Gandalf] => wizard
    )
    
    ответ дан too much php, с репутацией 54894, 21.10.2009
  • 1 рейтинг

    просто к вашему сведению - если вы хотите сериализовать ваши данные во что-то простое для чтения и понимания, как JSON, но с большим сжатием и более высокой производительностью, вы должны проверить пакет сообщений .

    ответ дан Hutch, с репутацией 6721, 12.04.2013
  • 1 рейтинг

    Во-первых, я изменил сценарий, чтобы сделать еще один сравнительный анализ (а также выполнить 1000 прогонов вместо 1):

    ответ дан Shawn Tolidano, с репутацией 111, 5.02.2017
  • 1 рейтинг

    Проверьте результаты здесь (извините за взлом, поместив код PHP в поле кода JS):

    http: // jsfiddle. net / newms87 / h3b0a0ha / встроенный / result /

    РЕЗУЛЬТАТЫ: serialize() и unserialize() значительно быстрее в PHP 5. 4 на массивах разного размера.

    Я сделал тестовый скрипт на реальных данных для сравнения json_encode и serialize и json_decode и unserialize. Тест проводился на системе кеширования на сайте электронной коммерции. Он просто берет данные, уже находящиеся в кэше, и проверяет время для кодирования / декодирования (или сериализации / десериализации) всех данных, и я помещаю их в легко видимую таблицу.

    Я запустил это на PHP 5. 4 хостинг-сервера.

    Результаты были очень убедительными, что для этих больших и малых наборов данных сериализация и десериализация были явными победителями. В частности, для моего случая использования json_decode и unserialize являются наиболее важными для системы кэширования. Unserialize был почти повсеместным победителем здесь. Обычно это было в 2-4 раза (иногда в 6 или 7 раз) быстрее, чем json_decode.

    Интересно отметить разницу в результатах от @ peter-bailey.

    Вот код PHP, используемый для генерации результатов:

     basename($file),
            'json_encode() Time (s)' => $json_encode_time,
            'json_decode() Time (s)' => $json_decode_time,
            'serialize() Time (s)'   => $serialize_time,
            'unserialize() Time (s)' => $unserialize_time,
            'Elements'               => $count,
            'Memory (KB)'            => $memory,
            'Max Depth'              => $depth,
            'json_encode() Win'      => ($json_encode_time > 0 && $json_encode_time < $serialize_time) ? number_format(($serialize_time / $json_encode_time - 1) * 100, 2) : '',
            'serialize() Win'        => ($serialize_time > 0 && $serialize_time < $json_encode_time) ? number_format(($json_encode_time / $serialize_time - 1) * 100, 2) : '',
            'json_decode() Win'      => ($json_decode_time > 0 && $json_decode_time < $serialize_time) ? number_format(($serialize_time / $json_decode_time - 1) * 100, 2) : '',
            'unserialize() Win'      => ($unserialize_time > 0 && $unserialize_time < $json_decode_time) ? number_format(($json_decode_time / $unserialize_time - 1) * 100, 2) : '',
        );
    }
    
    $files = glob(dirname(__FILE__) . '/system/cache/*');
    
    $data = array();
    
    foreach ($files as $file) {
        if (is_file($file)) {
            $result = run_test($file);
    
            if ($result) {
                $data[] = $result;
            }
        }
    }
    
    uasort($data, function ($a, $b) {
        return $a['Memory (KB)'] < $b['Memory (KB)'];
    });
    
    $fields = array_keys($data[0]);
    ?>
    
    
    $value) { ?>
    ответ дан newms87, с репутацией 498, 7.09.2014
  • 0 рейтинг

    THX - для этого кода теста:

    Мои результаты для массива, который я использую для конфигурации, являются следующими: JSON закодирован в 0. 0031511783599854 секунд
    PHP сериализован в 0. 0037961006164551 секунд
    json_encode() было примерно 20. На 47% быстрее, чем serialize() JSON закодирован в 0. 0070841312408447 секунд
    PHP сериализован в 0. 0035839080810547 секунд
    unserialize() было примерно 97. 66% быстрее, чем json_encode()

    Итак - проверьте это на своих данных.

    ответ дан mk182, с репутацией 11, 28.07.2010
  • 0 рейтинг

    Я бы предложил вам использовать Super Cache, который представляет собой механизм файлового кэша, который не будет использовать json_encode или serialize. Он прост в использовании и действительно быстр по сравнению с другим механизмом PHP Cache.

    https: // packagist. org / packages / smart-php / супер-кеш

    Пример:

    ')->set('');
    sCache::cache('myKey')->set('Key_value');
    
    //Retrieving cache value with a key
    echo sCache::cache('myKey')->get();
    ?>
    
    ответ дан shabeer, с репутацией 934, 19.06.2018
  • 0 рейтинг

    JSON лучше, если вы хотите сделать резервную копию данных и восстановить их на другом компьютере или через FTP.

    Например, с serialize, если вы храните данные на сервере Windows, загружаете их по FTP и восстанавливаете на Linux, они больше не могут работать из-за перекодирования charachter, потому что serialize хранит длину строк и в Юникод & gt; UTF-8, транскодирующий некоторый 1-байтовый символ, может иметь длину 2 байта, что приводит к сбою алгоритма.

    ответ дан Informate.it, с репутацией 9, 26.11.2011
  • 0 рейтинг

    Если подвести итог тому, что люди здесь говорят, json_decode / encode кажется быстрее, чем сериализация / десериализация, НО Если вы сделаете var_dump, тип сериализованного объекта будет изменен. Если по какой-то причине вы хотите сохранить тип, переходите к serialize!

    (попробуйте, например, stdClass vs array)

    сериализация / десериализация:

    Array cache:
    array (size=2)
      'a' => string '1' (length=1)
      'b' => int 2
    Object cache:
    object(stdClass)[8]
      public 'field1' => int 123
    This cache:
    object(Controller\Test)[8]
      protected 'view' => 
    

    JSON кодировать / декодировать

    Array cache:
    object(stdClass)[7]
      public 'a' => string '1' (length=1)
      public 'b' => int 2
    Object cache:
    object(stdClass)[8]
      public 'field1' => int 123
    This cache:
    object(stdClass)[8]
    

    Как вы можете видеть, json_encode / decode преобразует все в stdClass, что не очень хорошо, информация об объекте теряется. , , Так что решайте исходя из потребностей, особенно если это не только массивы. , ,

    ответ дан David Constantine, с репутацией 432, 30.07.2017