2011-11-22 24 views
11

Necesito almacenar una gran cantidad de texto en la base de datos mysql. Serán millones de registros con el tipo de campo LONGTEXT y el tamaño de la base de datos será enorme.Comprimir texto antes de almacenarlo en la base de datos

Por lo tanto, quiero preguntar, si hay una forma segura de comprimir el texto antes de almacenarlo en el campo TEXTO para ahorrar espacio, con la posibilidad de extraerlo de nuevo si es necesario?

Algo así como:

$archived_text = compress_text($huge_text); 
// saving $archived_text to database here 
// ... 

// ... 
// getting compressed text from database 
$archived_text = get_text_from_db(); 
$huge_text = uncompress_text($archived_text); 

¿Hay una manera de hacer esto con PHP o MySQL? Todos los textos están codificados en utf-8.

ACTUALIZACIÓN

Mi aplicación es un sitio web de gran cantidad de literatura, donde los usuarios pueden añadir sus textos. Aquí está la tabla tengo:

CREATE TABLE `book_parts` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `book_id` int(11) NOT NULL, 
    `title` varchar(200) DEFAULT NULL, 
    `content` longtext, 
    `order_num` int(11) DEFAULT NULL, 
    `views` int(10) unsigned DEFAULT '0', 
    `add_date` datetime DEFAULT NULL, 
    `is_public` tinyint(3) unsigned NOT NULL DEFAULT '1', 
    `published_as_draft` tinyint(3) unsigned NOT NULL DEFAULT '0', 
    PRIMARY KEY (`id`), 
    KEY `key_order_num` (`order_num`), 
    KEY `add_date` (`add_date`), 
    KEY `key_book_id` (`book_id`,`is_public`,`order_num`), 
    CONSTRAINT FOREIGN KEY (`book_id`) REFERENCES `books` (`id`) ON DELETE CASCADE 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 

Actualmente cuenta con unos 800k registros y pesos 4 GB, el 99% de las consultas son SELECT. Tengo todos los motivos para pensar que los números aumentan en forma de diagrama. No me gustaría almacenar textos en los archivos porque hay una lógica bastante pesada y mi sitio web tiene bastantes visitas.

+0

Si está almacenando datos binarios, use un campo BLOB, no texto. – Brad

+1

Es posible que desee reconsiderar su veto en el almacenamiento basado en archivos. No estoy seguro de lo que quiere decir con "lógica pesada", pero no veo cómo el almacenamiento de los textos en la base de datos será mejor que los archivos de un sitio con mucho tráfico. – grossvogel

Respuesta

12

¿Va a indexar estos textos? ¿Qué tan grande es la carga de lectura en este texto? Insertar carga?

Puede utilizar la compresión de datos InnoDB, de manera transparente y moderna. Ver docs para más información.

Si tiene textos muy grandes (digamos, cada texto está por encima de 10MB), entonces la buena idea es no almacenarlos en Mysql. Tienda comprimida por gzip textos en el sistema de archivos y solo punteros y meta en mysql. Puede expandir fácilmente su almacenamiento en el futuro y moverlo a, p. DFS.

Actualización: otro plus de almacenamiento de textos fuera de MySQL: la base de datos se mantiene pequeña y rápida. Menos: alta probabilidad de inconsistencia de datos.

Actualización 2: si tiene muchos recursos de programación, por favor, eche un vistazo a proyectos como este: http://code.google.com/p/mysql-filesystem-engine/.

Actualización final: Según su información, puede usar la compresión InnoDB, es lo mismo que ZIP. Puede comenzar con estos parametros:

CREATE TABLE book_parts 
(...) 
ENGINE=InnoDB 
ROW_FORMAT=COMPRESSED 
KEY_BLOCK_SIZE=8; 

tarde que se necesitan para jugar con KEY_BLOCK_SIZE. Ver SHOW STATUS LIKE 'COMPRESS_OPS_OK' y SHOW STATUS LIKE 'COMPRESS_OPS'. La relación de estos dos parámetros debe ser cercana a 1.0: Docs.

+0

Si está utilizando InnoDB, esa es la manera de ir. Sin embargo, el uso de un motor que no hace compresión ... También veo un montón de razones para no "solo almacenar punteros a los archivos" en la base de datos (y un montón de razones para hacerlo - TIMTOWTDI, y realmente depende lo que necesita) – Romain

+0

@ Oroboros102 eche un vistazo a la actualización. ¿Comprendí correctamente que la compresión innodb solo comprime índices? Que este no es mi caso ... –

+0

No, la compresión se usa tanto para los datos como para todos los índices (PK, secundario, compuesto). – Oroboros102

7

Si está comprimiendo (por ejemplo, gzip), entonces no use campos de texto de ningún tipo. No son binarios seguros. Los datos entrantes/salientes de los campos de texto están sujetos a la traducción de los juegos de caracteres, que probablemente (aunque no necesariamente) destruyan los datos comprimidos y le den un resultado dañado al recuperar/descomprimir el texto.

Utilice los campos BLOB en su lugar, que son binarios-transparentes y no a ninguna traducción de los datos.

+0

Gracias por la información sobre el tipo de datos. Pero, ¿qué hay de comprimir? –

+0

Comprimir eliminaría la capacidad de buscar el texto, ya que tendría que descomprimir para obtener la prueba en bruto de nuevo. Si nunca va a utilizar el DB para hurgar en el texto, no almacene el texto comprimido (o sin formato) en el DB en primer lugar. Almacenarlo externamente en un archivo y almacenar algunas referencias (nombre de archivo/ruta) en el DB en su lugar. –

+0

gzcompress funciona muy bien con este enfoque, pero tenga en cuenta: http://www.mysqlperformanceblog.com/2008/01/11/mysql-blob-compression-performance-benefits/ –

2

No hay ventajas en la compresión de textos grandes en una base de datos.

Éstos son los problemas que le esperan en el largo plazo:

  • Si el servidor se bloquea los datos pueden ser difíciles de recuperar.
  • No es ideal para la búsqueda.
  • Lleva más tiempo transferir los datos entre el servidor mysql y el navegador.
  • Requiere mucho tiempo para la copia de seguridad (sin usar la replicación).

creo que el almacenamiento de estos grandes textos en un archivo de disco será más fácil para:

  • copia de seguridad distribuido (rsync).
  • PHP para manejar la carga de archivos.
+0

No estoy de acuerdo. El tiempo que lleva descomprimir una transmisión gzip es irrelevante en cualquier servidor normal, en comparación con la latencia en línea, puede ignorarlo por completo. No necesita buscar en cada campo de texto, a menudo solo necesita acceder a él. – John

5

Podría ser mejor definir el campo de texto como blob, y comprimir los datos en PHP para ahorrar costos en la comunicación.

CREATE TABLE book_parts (
    ...... 
    content blob default NULL, 
    ...... 
) 

En PHP, use gzcompress y gzuncompress.

$content = '......'; 
$query = sprintf("replace into book_parts(content) values('%s') ", 
     mysql_escape_string(gzcompress($content))); 
mysql_query($query); 


$query = "select * from book_parts where id = 111 "; 
$result = mysql_query($query); 
if ($result && $row = mysql_fetch_assoc($result)) 
    $content = gzuncompress($row['content']); 
1

Puede usar las funciones php gzdeflate y gzinflate para el texto.

Cuestiones relacionadas