Сжатие текста перед его сохранением в базе данных - PullRequest
12 голосов
/ 22 ноября 2011

Мне нужно хранить очень большое количество текста в базе данных MySQL.Это будут миллионы записей с типом поля LONGTEXT, а размер базы данных будет огромным.

Итак, я хочу спросить, есть ли безопасный способ сжатия текста перед его сохранением в поле TEXT для экономии места, с возможностьючтобы извлечь его обратно, если необходимо?

Что-то вроде:

$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);

Есть ли способ сделать это с php или mysql?Все тексты имеют кодировку utf-8.

ОБНОВЛЕНИЕ

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

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 

В настоящее время она имеет около 800 тыс. Записей и весит 4 ГБ, 99% запросов - это SELECT.У меня есть все основания полагать, что цифры увеличиваются схематически.Я не хотел бы хранить тексты в файлах, потому что вокруг довольно тяжелая логика, и у моего сайта довольно много посещений.

Ответы [ 6 ]

13 голосов
/ 22 ноября 2011

Собираетесь ли вы проиндексировать эти тексты. Насколько велика нагрузка на чтение этих текстов? Вставить нагрузку?

Вы можете использовать сжатие данных InnoDB - прозрачный и современный способ. См. документы для получения дополнительной информации.

Если у вас есть действительно огромные тексты (скажем, каждый текст размером более 10 МБ), то лучше не хранить их в Mysql. Храните сжатые тексты gzip в файловой системе и только указатели и мета в mysql. Вы можете легко расширить свое хранилище в будущем и переместить его, например, в. ДФС.

Обновление: еще один плюс хранения текстов вне Mysql: БД остается маленькой и быстрой. Минус: высокая вероятность несоответствия данных.

Обновление 2: если у вас много ресурсов программирования, пожалуйста, посмотрите на проекты, подобные этому: http://code.google.com/p/mysql-filesystem-engine/.

Окончательное обновление: Согласно вашей информации, вы можете просто использовать сжатие InnoDB - оно аналогично ZIP. Вы можете начать с этих параметров:

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

Позже вам нужно будет поиграть с KEY_BLOCK_SIZE. См. SHOW STATUS LIKE 'COMPRESS_OPS_OK' и SHOW STATUS LIKE 'COMPRESS_OPS'. Соотношение этих двух параметров должно быть близко к 1,0: Документы .

7 голосов
/ 22 ноября 2011

Если вы сжимаете (например, gzip), то не используйте поля TEXT любого рода. Они не бинарно-безопасны. Данные, поступающие в / выходящие из текстовых полей, подлежат переводу набора символов, который, вероятно, (хотя и не обязательно) искажает сжатые данные и дает вам искаженный результат при извлечении / распаковке текста.

Вместо этого используйте BLOB-поля, которые являются двоичными и прозрачными и не переводят данные.

6 голосов
/ 19 декабря 2014

Может быть лучше определить текстовое поле как blob и сжимать данные в PHP, чтобы сэкономить расходы на связь.

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

В PHP используйте gzcompress и 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']);
2 голосов
/ 22 ноября 2011

Вы также можете использовать опцию COMPRESS, чтобы включить сжатие пакетов. Прочитайте некоторую информацию об этой опции:

Для PHP я нашел это - MYSQLI_CLIENT_COMPRESS для функции mysqli_real_connect .

1 голос
/ 11 января 2016

Вы можете использовать php функции gzdeflate и gzinflate для текста.

0 голосов
/ 22 ноября 2011

Нет смысла сжимать большие тексты в базу данных.

Вот проблемы, с которыми вы можете столкнуться в долгосрочной перспективе:

  • В случае сбоя сервера данные могут бытьтрудно восстановить.
  • Не идеально подходит для поиска.
  • Для передачи данных между сервером mysql и браузером требуется дополнительное время.
  • Время, необходимое для резервного копирования (не используетсярепликация).

Я думаю, что хранить эти большие тексты в файле на диске будет проще:

  • Распределенная резервная копия (rsync).
  • PHP дляобрабатывать загрузку файлов.
...