Pregunta Método preferido para almacenar matrices PHP (json_encode vs serialize)


Necesito almacenar una matriz asociativa multidimensional de datos en un archivo plano para fines de almacenamiento en caché. De vez en cuando puedo encontrar la necesidad de convertirlo a JSON para utilizarlo en mi aplicación web, pero la gran mayoría de las veces voy a usar la matriz directamente en PHP.

¿Sería más eficiente almacenar la matriz como JSON o como una matriz serializada de PHP en este archivo de texto? He mirado alrededor y parece que en las versiones más nuevas de PHP (5.3), json_decode es en realidad más rápido que unserialize.

Actualmente me estoy inclinando por el almacenamiento de la matriz como JSON, ya que creo que es más fácil de leer por un humano si es necesario, se puede usar tanto en PHP como en JavaScript con muy poco esfuerzo, y por lo que he leído, incluso podría ser más rápido para decodificar (sin embargo, no estoy seguro acerca de la codificación).

¿Alguien sabe de algún escollo? ¿Alguien tiene buenos puntos de referencia para mostrar los beneficios de rendimiento de cualquiera de los métodos?


545
2018-04-29 20:09


origen


Respuestas:


Depende de tus prioridades

Si el rendimiento es su característica de conducción absoluta, entonces use la más rápida. Solo asegúrate de tener una comprensión completa de las diferencias antes de tomar una decisión

  • diferente a serialize() necesita agregar un parámetro extra para mantener intactos los caracteres UTF-8: json_encode($array, JSON_UNESCAPED_UNICODE)  (de lo contrario, convierte los caracteres UTF-8 en secuencias de escape Unicode).
  • JSON no tendrá memoria de la clase original del objeto (siempre se restauran como instancias de stdClass).
  • No puedes aprovechar __sleep() y __wakeup() con JSON
  • Por defecto, solo las propiedades públicas se serializan con JSON. (en PHP>=5.4 puedes implementar JsonSerializable para cambiar este comportamiento).
  • JSON es más portátil

Y probablemente haya otras diferencias en las que no puedo pensar en este momento.

Una prueba de velocidad simple para comparar los dos

<?php

ini_set('display_errors', 1);
error_reporting(E_ALL);

// Make a big, honkin test array
// You may need to adjust this depth to avoid memory limit errors
$testArray = fillArray(0, 5);

// Time json encoding
$start = microtime(true);
json_encode($testArray);
$jsonTime = microtime(true) - $start;
echo "JSON encoded in $jsonTime seconds\n";

// Time serialization
$start = microtime(true);
serialize($testArray);
$serializeTime = microtime(true) - $start;
echo "PHP serialized in $serializeTime seconds\n";

// Compare them
if ($jsonTime < $serializeTime) {
    printf("json_encode() was roughly %01.2f%% faster than serialize()\n", ($serializeTime / $jsonTime - 1) * 100);
}
else if ($serializeTime < $jsonTime ) {
    printf("serialize() was roughly %01.2f%% faster than json_encode()\n", ($jsonTime / $serializeTime - 1) * 100);
} else {
    echo "Impossible!\n";
}

function fillArray( $depth, $max ) {
    static $seed;
    if (is_null($seed)) {
        $seed = array('a', 2, 'c', 4, 'e', 6, 'g', 8, 'i', 10);
    }
    if ($depth < $max) {
        $node = array();
        foreach ($seed as $key) {
            $node[$key] = fillArray($depth + 1, $max);
        }
        return $node;
    }
    return 'empty';
}

512
2018-04-29 20:21



JSON es más simple y más rápido que el formato de serialización de PHP y debe ser utilizado a no ser que:

  • Está almacenando matrices profundamente anidadas: json_decode(): "Esta función devolverá falso si los datos codificados JSON son más profundos que 127 elementos".
  • Está almacenando objetos que deben ser deserializados como la clase correcta
  • Estás interactuando con versiones antiguas de PHP que no son compatibles con json_decode

222
2018-04-29 20:13



He escrito un blog sobre este tema: "Guarde en caché una matriz grande: JSON, serialize o var_export?"En esta publicación se muestra que serializar es la mejor opción para matrices de tamaño pequeño a grande. Para arreglos muy grandes (> 70 MB), JSON es la mejor opción.


55
2017-07-07 14:20



Usted también puede estar interesado en https://github.com/phadej/igbinary - que proporciona un 'motor' de serialización diferente para PHP.

Mis cifras de "rendimiento" arbitrario / arbitrario, utilizando PHP 5.3.5 en una plataforma de 64 bits muestran:

JSON:

  • JSON codificado en 2.180496931076 segundos
  • JSON decodificado en 9.8368630409241 segundos
  • tamaño de "String" serializado: 13993

PHP nativo:

  • PHP serializado en 2.9125759601593 segundos
  • PHP sin serializar en 6.4348418712616 segundos
  • Tamaño serial de "String": 20769

Igbinario:

  • GANAR igbinario serializado en 1.6099879741669 segundos
  • GANAR igbinrario no serializado en 4.7737920284271 segundos
  • GANAR Tamaño de "String" serializado: 4467

Por lo tanto, es más rápido igbinary_serialize () e igbinary_unserialize () y utiliza menos espacio en disco.

Utilicé el código fillArray (0, 3) como se indicó anteriormente, pero hice que las teclas de matriz fueran cadenas más largas.

igbinary puede almacenar los mismos tipos de datos que la serialización nativa de PHP (así que no hay problema con los objetos, etc.) y puede decirle a PHP5.3 que lo use para el manejo de la sesión si así lo desea.

Ver también http://ilia.ws/files/zendcon_2010_hidden_features.pdf - diapositivas específicas 14/15/16


48
2018-01-27 18:53



Acabo de probar serializado y json codificar y decodificar, más el tamaño que tomará la cadena almacenada.

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

Podemos concluir que JSON codifica más rápido y resulta una cadena más pequeña, pero la desestratificación es más rápida para decodificar la cadena.


23
2017-07-10 23:44



Si está almacenando en caché información que en última instancia querrá "incluir" en un momento posterior, puede intentar usar var_export. De esta forma solo tomas el hit en "serializar" y no en "deserializar".


14
2018-04-29 23:04



Aumenté la prueba para incluir el rendimiento de la deserialización. Aquí están los números que obtuve.

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() 

Entonces, json parece ser más rápido para la codificación pero lento en la decodificación. Por lo tanto, podría depender de su aplicación y de lo que espera hacer más.


11
2017-11-23 19:14



Parece que serialize es el que voy a usar por dos razones:

  • Alguien señaló que la deserialización es más rápida que json_decode y un caso de "lectura" parece más probable que un caso de "escritura".

  • He tenido problemas con json_encode cuando tengo cadenas con caracteres UTF-8 no válidos. Cuando eso sucede, la cadena termina siendo vacía, causando la pérdida de información.


8
2018-06-27 00:46



Un tema realmente agradable y después de leer las pocas respuestas, quiero compartir mis experimentos sobre el tema.

Tengo un caso de uso donde se debe consultar una tabla "grande" casi cada vez que hablo con la base de datos (no preguntes por qué, solo un hecho). El sistema de caché de la base de datos no es apropiado ya que no almacenará en caché las diferentes solicitudes, así que pensé en los sistemas de caché de php.

Lo intenté apcu pero no se ajustaba a las necesidades, la memoria no es lo suficientemente confiable en este caso. El siguiente paso fue almacenar en caché un archivo con serialización.

La tabla tiene 14355 entradas con 18 columnas, esas son mis pruebas y estadísticas al leer el caché serializado:

JSON:

Como todos han dicho, el mayor inconveniente con json_encode/json_decode es que transforma todo en una StdClass instancia (u Objeto). Si necesita buclearlo, transformarlo en una matriz es lo que probablemente hará, y sí, está aumentando el tiempo de transformación.

tiempo promedio: 780.2 ms; uso de memoria: 41.5MB; tamaño del archivo de caché: 3.8MB

Msgpack

@hutch menciona msgpack. Bonito sitio web. Vamos a intentarlo, ¿o sí?

tiempo promedio: 497 ms; uso de memoria: 32MB; tamaño del archivo de caché: 2.8MB

Eso es mejor, pero requiere una nueva extensión; compilando a veces personas temerosas ...

IgBinary

@GingerDog menciona igbinario. Tenga en cuenta que he configurado el igbinary.compact_strings=Offporque me importa más leer interpretaciones que el tamaño del archivo.

tiempo promedio: 411,4 ms; uso de memoria: 36.75MB; tamaño del archivo de caché: 3.3MB

Mejor que el paquete de mensajes. Aún así, esto también requiere compilación.

serialize/unserialize

tiempo promedio: 477.2 ms; uso de memoria: 36.25MB; tamaño del archivo de caché: 5.9MB

Mejores actuaciones que JSON, cuanto más grande es la matriz, más lenta json_decode es, pero ya eres nuevo.

Esas extensiones externas están reduciendo el tamaño del archivo y parece genial en el papel. Los números no mienten *. ¿De qué sirve compilar una extensión si obtiene casi los mismos resultados que tendría con una función PHP estándar?

También podemos deducir que, según sus necesidades, elegirá algo diferente a otra persona:

  • IgBinary es realmente agradable y funciona mejor que MsgPack
  • Msgpack es mejor para comprimir tus datos (ten en cuenta que no probé el igbinario opción compact.string).
  • ¿No quieres compilar? Usa los estándares.

¡Eso es todo, otra comparación de métodos de serialización para ayudarlo a elegir el uno!

* Probado con PHPUnit 3.7.31, php 5.5.10 - solo decodificación con un hardrive estándar y un viejo CPU de doble núcleo - números promedio en 10 pruebas de casos de uso iguales, tus estadísticas pueden ser diferentes


7
2018-04-17 14:35