Мне поручено освободить свободное место на диске. <br/><br/> База данных уже прошла процесс сжатия (отшринкована), и теперь я рассматриваю возможность использования функции compression. <br/><br/> У меня возник вопрос: как именно с помощью этой функции можно уменьшить размер базы данных? Необходимо ли применять сжатие для каждой конкретной таблицы, или существует возможность сжать всю базу данных сразу?
Сжатие данных в MS SQL Server может быть выполнено с помощью функции, называемой **данных компрессия (data compression)**. Она позволяет уменьшить размер данных с помощью различных алгоритмов сжатия, которые применяются к строкам и страницам данных. Это может помочь освободить место на диске и улучшить производительность запросов. ### Основные способы сжатия 1. **Row Compression (Сжатие строк)**: - Уменьшает объем хранения данных за счет оптимизации хранения фиксированных и переменных типов данных. - Сокращает размер строк путем удаления лишних пробелов и ненужных байтов, которые не используются. 2. **Page Compression (Сжатие страниц)**: - Затрагивает всю страницу данных (обычно 8 КБ) и использует более сложные алгоритмы, такие как сжатие последовательностей и уникальных значений, что может значительно уменьшить размер страниц. - Включает в себя все преимущества `Row Compression` и добавляет дополнительный уровень сжатия. 3. **Columnstore Compression**: - Используется для столбцовых хранилищ данных (Columnstore Indexes) и позволяет достигать значительного снижения объема данных за счет сжатия на уровне столбцов. ### Как применять сжатие - **Сжатие таблиц**: Вы можете применить компрессию к каждой конкретной таблице с помощью команды T-SQL. Например: ```sql ALTER TABLE [TableName] REBUILD WITH (DATA_COMPRESSION = PAGE); ``` - **Сжатие индексов**: Компрессию также можно применять к индексам отдельно: ```sql ALTER INDEX [IndexName] ON [TableName] REBUILD WITH (DATA_COMPRESSION = ROW); ``` - **Сжатие всей базы данных сразу**: К сожалению, MS SQL Server не поддерживает сжатие всех таблиц и индексов базы данных одновременно с одной командой. Вам нужно будет перебирать каждую таблицу и индекс. - **Скрипт для массового сжатия**: Вы можете написать скрипт, который переберет все таблицы и индексы и применит к ним компрессию. Примерно так: ```sql DECLARE @TableName NVARCHAR(256); DECLARE TableCursor CURSOR FOR SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE'; OPEN TableCursor; FETCH NEXT FROM TableCursor INTO @TableName; WHILE @@FETCH_STATUS = 0 BEGIN DECLARE @SQL NVARCHAR(MAX); SET @SQL = 'ALTER TABLE ' + QUOTENAME(@TableName) + ' REBUILD WITH (DATA_COMPRESSION = PAGE);'; EXEC sp_executesql @SQL; FETCH NEXT FROM TableCursor INTO @TableName; END CLOSE TableCursor; DEALLOCATE TableCursor; ``` ### Рекомендации - Перед применением сжатия рекомендуется оценить степень использования каждой таблицы/индекса и понять, насколько они заполняют пространство. - Также стоит учитывать возможное влияние на производительность, так как сжатие может потребовать дополнительных ресурсов для распаковки данных при выполнении запросов. - Не забудьте протестировать изменения в безопасной среде перед развертыванием на производственной базе данных. Сжатие может существенно помочь в управлении пространством, но важно рассмотреть его использование в контексте текущих потребностей вашей базы данных и приложения.
Но при нынешних ценах на дисковое пространство попытка добыть пару лишних мегабайт сжатием - крайне неразумное занятие. Дополнительные процессорные ресурсы на него стоят куда как дороже.люто плюсую.
Но если прямо очень нужно, то советую вместо сжатия средствами БД, попробовать сжать средствами файловой системы (например btrfs - zstd, 16 уровней сжатия), можно поиграть с разным размером кластера, что может сильно повлиять на результат... особенно если в базе данных соседние поля с одинаковыми данными, а движок их упаковывает независимо.
Скорость записи в базу данных на сжатом диске сильно упадет, особенно если делать большой размер кластера (так как это увеличивает степень сжатия), но вот скорость чтения, особенно с hdd, даже может подрасти (особенно при хорошей степени сжатия), но должно много всего совпасть.
НАСТОЯТЕЛЬНО рекомендую файлы индексов не сжимать, за исключением случаев, когда они целиком и полностью влезают в оперативную память и запись в базу данных не производится.
ОБЯЗАТЕЛЬНОЕ тестирование всей конструкции на реальных данных перед запуском в продакшен, иначе можно получить проблему, и конечно же бакапы, без них ничего делать даже не начинай.
p.s. наилучшее сжатие можно получить, если грамотно его реализовать на стороне самого приложения, ведь его разработчик знает, где какие данные как лежат, как их можно эффективно перераспределить и главное, есть библиотеки типа того же zstd, когда можно держать несколько словарей для сжимаемых данных, специально собранных под свои наборы данных,.. отличный пример сжатие xml/json файлов, где теги/атрибуты могут занимать до 90% пространства,.. и при маленьком размере сжимаемого куска, словарь на них будет в каждом куске свой.. а вот общий словарь для всего пакета файлов позволит на порядок сократить их объем.
p.p.s. само собой, замена xml/json на правильно созданный protobuf исключит эту проблему в зачатке
Я просоединяюсь к совету выше. На тему того что самое эффективное уплотение информции
можно сделать на уровне разработки приложения.
Я-бы предложил не сжимать всю базу а проанализировать, какие таблицы и какие поля занимают
80% всего пространства. (Процены я взял с головы по принципу Паретто. Вы можете взять любой
процент. Можно 90 или 70 не суть важно. Важно чтобы не закапыватья м мелочах.)
Из опыта других БД. (Не MS-SQL). Часто бывало что потребителем места были BLOB-поля где
лежали какие-то несуразные и никому не нужные документы. Аттачменты. Картинки. Копии
email из переписок с пользователем и многое другое. Были ситуации когда причиной роста
БД были старые архивные записи в таблице которые почему-то были забыты. Они должны
были удаляться но из за бага не удалялись.
Хорошая практика в данном случае - убрать из БД все длинные текстовые документы
или положить их в gzip на уровне самого приложения например. Обычно такие поля
не участвуют напрямую в операциях OLTP и их сжатие ни на что особо не влияет.
Почти все современные БД имеют очень хорошую плотность информации на мегабайт
и если админ что-то там шринковал или уплотнял - то это носит временную меру. Через
некоторое время БД возвращается к той плотности как и была раньше вследствие
updates например.
По поводу ROW level/block level сжатия. Я не специалист в MS_SQL, но обычно это надо
предварительно тестировать под нагрузкой на PROD для всех DBMS в общем то.
Велика вероятность падения производительности а это, сами понимаете слишком
большая цена за экономию. И диски в наше время значительно дешевле скажем чем 10 лет назад.