Сегодня предлагаем обсудить сжатие данных в Oracle.
 
Ситуация: один наш крупный клиент в сфере телекома стремится нарастить абонентскую базу, поощряет потребление услуг и рост трафика. Это позволяет развиваться компании в целом и каждой её системе в отдельности, включая нашу систему взаиморасчётов с партнёрами — Partner Relationships Managment.

Проблема: регулярный прирост информации в БД на 0.6 TБ в месяц превращается в 7.2 TБ в год. При этом востребованной для изменений является информация только за последние два-три месяца. Остальные данные накапливаются и хранятся для отчётности. При таком подходе база разрастается очень быстро, а каждый SSD системы хранения данных становится на вес золота. К тому же необходимо поддерживать согласованность резервной и тестовой БД. 

Есть два выхода: закидывать в базы, как «в топку», бесконечное количество дисков, либо оптимизировать хранение информации. Мы выбрали второе.

В этой статье главный инженер-программист по бизнес-системам Кирилл Солдатов расскажет, что конкретно сделали в Nexign. Информация будет полезна всем, кто как и мы сталкивается с необходимостью управления большими массивами в БД Oracle.

Интро: почему нам надо сжимать данные

Каждый месяц после расчёта клиентских начислений в мобильной, фиксированной связи и интерконнекте (системе расчетов между операторами), мы проводим свой биллинг для определения вознаграждения дилерам и агентам, которые работают с оператором. Для этого выгружаем из биллинговой системы используемую абонентами НСИ, агрегированные начисления клиентов за месяц, информацию о потреблённых услугах и подключенных пакетах, данные о регистрации абонентов в точках продаж.

За 10 лет работы системы количество данных могло бы стать неприемлемо большим, более 80 ТБ (7,2 ТБ в год на 10 лет, плюс технологические данные и результаты расчётов). По факту на март 2024 г. имеем 41 TБ. Чтобы понять, как менялся объем хранилища за весь период, рассмотрим график 1. На нем приведена наглядная статистика количества данных с марта 2019 года по март 2024 года за каждый месяц в терабайтах.

Статистика занимаемого места в файлах БД PRM
Статистика занимаемого места в файлах БД PRM

На момент начала сбора статистики в базе данных было занято 32 ТБ и за 5 лет это значение выросло до 41 ТБ Такая математика не совпадает с заявленным мною ранее приростом 7.2 ТБ в год. И на то есть причины:

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

  2. Также выполнялся функционал сжатия старых данных для субпартиций, хранящих данные за периоды старше 12 месяцев, об этом я буду расказывать в статье ниже.

Так как данные моложе 12 месяцев ещё не сжимались, рассмотрим меньший поздний период за последний год — с марта 2023 по март 2024.

За 2023-2024 гг. наблюдается линейный прирост занимаемого места, и субпартиции за этот период ещё не архивировались. На  основании этих данных получаем средний ежемесячный актуальный прирост 0.57 ТБ. Это значение сопоставимо со средним значением суммы субпартиций для каждого месяца за последний год — 0.414 ТБ.

Статистика занятого места за период с марта 2023 по март 2024, без сжатия
Статистика занятого места за период с марта 2023 по март 2024, без сжатия

Остальные данные (из 0,57 ТБ) добавляются инкрементально в непартиционированные таблицы, поэтому в статистику в следующей таблице не попадают. Статистика размера субпартиций за март 2023 — март 2024 года:

Месяц

Сумма субпартиций за период, гб. 

2023.03

373,4631

2023.04

380,2969

2023.05

376,6112

2023.06

381,6728

2023.07

385,8993

2023.08

392,797

2023.09

417,98

2023.10

430,4785

2023.11

440,8479

2023.12

440,8199

2024.01

441,5043

2024.02

463,7789

2024.03

454,9307

в среднем

413,9

Для сравнения рассмотрим график прироста занимаемого места за ранний период с февраля 2020 года по апрель 2022 года.

Статистика за февраль 2020 — апрель 2022, с активным сжатием
Статистика за февраль 2020 — апрель 2022, с активным сжатием

Для этого периода уже работает функционал сжатия старых данных. Благодаря чему среднее значение ежемесячного прироста данных за период со сжатием получилось 0.38 ТБ против 0.57 ТБ для периода, когда архивирование ещё не проводилось. Получаем снижение ежемесячного прироста занимаемого места в 1.5 раза, что подтверждает эффективность применяемого метода сжатия старых субпартиций. Давайте рассмотрим функционал партиционирования и архивирования Oracle, который помог нам добиться такого результата.

Что мы сделали, чтобы остановить стремительный рост БД

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

Каждая партиция может обладать отдельными физическими атрибутами. К примеру, включённое или выключенное сжатие, тип сжатия, конфигурация физического хранения, табличное пространство. Эти возможности образовывают структуру, которая позволяет точнее настраивать доступность и производительность. В дополнение, каждая партиция может управляться индивидуально, что упрощает и снижает время на формирование бэкапов и администрирование.

Для частично или полностью партиционированных таблиц работают все правила и операции доступа и управления таблицами, как и для непартиционированных. Доступ и управление частично или полностью партиционированными таблицами такой же, как и для непартиционированных.

У нас реализовано LIST партиционирование по списку значений и RANGE субпартиционирование по дате события, а именно по месяцу. В этой статье буду рассказывать только про деление субпартиций по месяцам.

Теперь поговорим про сжатие

Возникает вопрос, если сжатые таблицы не отличаются по способам работы с ними от обычных — почему бы не применить компресс (сжатие) сразу ко всей таблице? Зачем возиться с партиционированием?
 Для ответа давайте разберём, как работает сжатие данных в Oracle.

Возможность сжатия таблиц реализуется путём удаления дублирующихся значений из таблиц базы. Сжатие выполняется на уровне блоков. Когда таблица определена как сжатая, сервер занимает место в каждом блоке для хранения одной копии, встречающейся в нескольких местах. Это зарезервированное место называют таблицей символов (symbol table). 

Помеченная для сжатия информация хранится только в таблице символов, а не в строках данных. При появлении в строке данных, помеченных для сжатия, вместо самих данных запоминается указатель на соответствующую информацию в таблице символов. Экономия места достигается за счёт удаления избыточных копий в таблице.

Сжатие помогает сократить занимаемое место на диске, снижает количество потребляемой памяти буфером БД для формирования кэша, и может благоприятно сказаться на повышении скорости выполнения запросов при чтении данных.

Сжатие бывает трёх видов:

  1. Basic Table Compression — высокий уровень сжатия, низкие накладные расходы CPU. Возможно сжатие только при direct-path загрузке (INSERT /*+ APPEND */ INTO ... SELECT ... или CREATE TABLE ... AS SELECT... или через SQL Loader с директивой DIRECT=TRUE). Обновление basic-сжатых строк вызывает немедленную распаковку и возврат к хранению в обычном строчном виде. Поэтому такой вариант неоптимален, если сжатые данные будут подвержены частому и массовому изменению.

  2. Advanced Row Compression — высокий уровень сжатия, низкие накладные расходы CPU, поддерживает сжатие «на лету» при OLTP-операциях (например, INSERT INTO x VALUES ...).  Это реализуется путем отсрочки сжатия до тех пор, пока в блоке не будет достаточно данных, чтобы их стоило компресссировать. Такой метод может сжимать строки в блоке, которые были вставлены по отдельности в разных сеансах и в разное время. Степень сжатия немного хуже или сопоставима со сжатием basic. Но главный недостаток - опция расширенного сжатия (Advanced Compression Option) приобретается у компании Oracle за дополнительную плату.

  3. Hybrid Columnar Compression (HCC) — этот вариант подразделяется на Warehouse compression и Archive compression, для которых уровень сжатия и затраты на CPU зависят от выбранного уровня LOW или HIGH.
     HCC позволяет сжать таблицу в 10-50 раз! Такой результат достигается благодаря тому, что данные в таблицах с гибридным сжатием хранятся с объединением по столбцам, а не по строкам. Это позволяет оптимизировать сжатие и минимизировать дубли:

Но такое преобразование формы хранения негативно сказывается на производительности. Для нас такой вариант не подходит. Archive compression, как и следует из названия, идеально подходит для сжатия таблиц со старыми данными, к которым отсутствуют частые обращения.

Для типов Basic, Warehouse и Archive Compression сжатие данных будет применяться при первом включении для субпартиции и при последующих вставках (изменениях), но только для вставляемых пачек bulk, или массивов array.

В базах системы Nexign Partner Relationships Managment мы применяем Basic compression — это обсуловлено логикой работы с данными. В начале каждого месяца нарезаются субпартиции для хранения данных нового периода. После биллинга (мобильных абонентов и клиентов фиксированной связи) свежесозданные партиции разово наполняются данными и хранятся так год, после чего к ним применяется сжатие.

В течение двенадцати месяцев в ходе эксплуатации системы и разбора внутрикорпоративных обращений штучные данные могут изменяться сотрудниками, а более старые данные актуализировать нам приходится крайне редко.

В каждую субпартицию данные загружаются массово и один раз в первые дни месяца, после чего редко претерпевают изменения. В таком случае при отсутствии многочисленных и постоянных DML-операций (insert, update, merge - на которые не действует онлайн-сжатие), вариант basic compression является самым подходящим. Advanced требует дополнительных денежных затрат, а Hybrid — бóльших железных мощностей и времени на выполнение.

Как работает сжатие данных в Nexign

Как я отметил ранее, мы сжимаем новые данные не сразу, как они появляются, а только спустя год использования. Я настроил автоматический запуск процессов сжатия на середину каждого месяца, когда нагрузка от ежемесячных расчётов уже прошла (а жажда приключений ещё нет). Алгоритм выглядит так:

  1. По заранее подготовленному списку таблиц строится курсор, выбирающий субпартиции, хранящие данные с глубиной более 12 месяцев. 

  2. В цикле по результирующему набору курсора отключаются bitmap индексы, если такие есть для таблицы.

  3. Выполняется сжатие субпартиции в несколько параллелей (в 8, если это кому-то интересно).

  4. Пересобирается индекс для обработанной партиции.

  5. Пересобирается глобальный индекс уровня всей таблицы.

Немного обзорной статистики: в нашем случае на анализ и сжатие субпартиции, хранящей 78 млн. строк, 15 гб. данных, Oracle в 8 параллелей тратит 2 минуты. Всего ежемесячно мы обрабатываем до 1400 субпартиций разной степени наполненности и пересобираем столько же их индексов.

Благодаря тому, что процессы работают в 8 потоков по 8 параллелей, эти работы укладываются в тех. окно — 2 часа в ночное время. То есть работы проводятся незаметно для бизнес-пользователей.

Сжатие партиций и субпартиций

Сжатие данных может быть применимо как для таблиц в целом, так и к отдельным её партициям и субпартициям. Выполняется всё простой командой (в зависимости от типа партиционирования):

alter table TABLE_OWNER.TABLE_NAME compress;

alter table TABLE_OWNER.TABLE_NAME move partition PARTITION_NAME compress;

alter table TABLE_OWNER.TABLE_NAME move subpartition SUBPARTITION_NAME compress;

Для оптимального использования мощностей БД можно добавить параллельности parallel N. Также может потребоваться перенести старые данные в отдельное табличное пространство. Тогда дописываем в команду move tablespace TABLESPACE_NAME. К примеру, такое архивное ТП можно физически разместить на отдельных более дешёвых дисках СХД.

Сжатие индексов

Для индексов ситуация аналогичная — к ним также можно применить сжатие и для всего индекса, и для его частей. Вне зависимости от компрессии самой таблицы.

alter index INDEX_OWNER.INDEX_NAME compress;

alter index INDEX_OWNER.INDEX_NAME move partition PARTITION_NAME compress;

alter index INDEX_OWNER.INDEX_NAME move subpartition SUBPARTITION_NAME compress;

Важно отметить особенность работы с bitmap-индексами. Перед сжатием их необходимо выключить, а после компресса — пересобрать.

alter index INDEX_OWNER.INDEX_NAME unusable;

alter index INDEX_OWNER.INDEX_NAME rebuild;

Такой вариант допустим, если наш индекс един и неделим. В случае если индекс партиционирован — перестраивать необходимо каждую его минимальную часть.

alter index INDEX_OWNER.INDEX_NAME rebuild partition PARTITION_NAME;

alter index INDEX_OWNER.INDEX_NAME rebuild subpartition SUBPARTITION_NAME;

Также Oracle позволяет сжимать отдельные столбцы в составных индексах. Но это уже совсем другая история.

Подводим итоги

В разных продуктах для разных вариантов использования баз данных можно подобрать свой тип сжатия: Basic Table Compression, Advanced Row Compression, Hybrid Columnar Compression (HCC). Архивирование особенно удобно использовать в паре с разделением таблиц на партиции и субпартиции.

Функционал архивирования в Oracle позволяет значительно оптимизировать хранимые массивы данных. В нашем случае удалось снизить ежемесячный прирост в 1.5 раза — с 0.6 ТБ до 0.38 ТБ. Считаю, что для базы в 40 ТБ (а их у нас три) — это хороший результат. Он позволит сэкономить на закупке очередных СХД.

 Надеюсь, мой опыт поможет оптимизировать хранение данных и в ваших системах!

Комментарии (17)


  1. Sabirman
    14.10.2024 13:51

    >> Сжатие на уровне блоков

    А какой у вас размер блока ?


    1. Nexign Автор
      14.10.2024 13:51

      Размер блока у нас 8 килобайт, дефолтное значение.


  1. IceGlance
    14.10.2024 13:51

    А глобальные индексы для чего используются?


    1. FancyStacy
      14.10.2024 13:51

      Для поиска по всей таблице, а не отдельным секциям. Что не ясно?


    1. ducrow
      14.10.2024 13:51

      Различия между глобальными и локальными идексами выражаются в их отношениях с таблицей.
      Для глобальных индексов - один раздел индекса соотносится со многими разделами таблицы.
      Для локальных - один раздел индекса - один раздел таблицы.

      Глобальные индексы секционируются независимо от базовых таблиц. Например, каждый раздел индекса может содержать ключи, которые относятся к разным разделам или подразделам таблицы.

      По идее, так как при компрессии мы трогаем только субпартицию, то ожидается что и перестраивать нужно только индекс для этого раздела.
      Но нет. В нашем случае, для оптимальной работы Оракл требует пересобрать индекс всей таблицы.


  1. orefkov
    14.10.2024 13:51

    "Проводились активности по удалению" - это какой-то новый канцелярит?


    1. ducrow
      14.10.2024 13:51

      Просто протранкейтить всё что не нравится нельзя. Поэтому приходится скрупулёзно выбирать, анализировать, отсеивать что не нужно и перед окончательным удалением проводить регресс-тестирование. Эта формулировка призвана подчеркнуть трудоёмкость процесса)


  1. pihel
    14.10.2024 13:51

    Для HCC нужна exadata, не всем подойдет


    1. FancyStacy
      14.10.2024 13:51

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


  1. molnij
    14.10.2024 13:51

    Было 0.6х12=7.2Tb в год, стало 0.38*12=4.56Тб в год.

    Каким образом это могло спасти от первого выхода "закидывать в базы, как «в топку», бесконечное количество дисков" пока не очень понятно.. Стало нужно всего лишь в полтора раза меньше дисков. Но это же даже не кратное улучшение

    Вариант закидывать старые партиции с холодными данными на hdd не подходил? Я правда, никогда не пробовал оракл в гетерогенной среде, может и чушь спорол..


    1. FlyingDutchman
      14.10.2024 13:51

      Для архивных партий как раз отлично подойдёт большой дисковый массив из более дешёвых (не-SSD) дисков, на котором можно создать один или более read-only tablespace и переносить архивные сжатые партиции туда. Заодно и бэкап оптимизируется, Rman не будет каждый раз бэкапить read-only датафайлы.


      1. FancyStacy
        14.10.2024 13:51

        Если включить оптимизацию бекапа он и так не будет копировать файлы, которые не поменялись. Ридонли только чтоб предотвратить изменения, где и когда они не нужны


        1. FlyingDutchman
          14.10.2024 13:51

          У read/write датафайлов всегда меняется header - туда пишется последний scn. Даже если не было никаких изменений данных в этих датафайлах. И такие датафайлы будут бэкапиться при level 0 бэкапе, увы. Или вы про BCT (block change tracking), когда при level 1 бэкапе будут бэкапиться будут лишь измененные блоки?


    1. ducrow
      14.10.2024 13:51

      Не соглашусь, тут разница принципиальна) Стало нужно аж в полтора раза меньше дисков.
      При выборе варианта между "нужно много денег на СХД" и "нужно в полтора раза меньше денег на СХД" - бизнес обычно выбирает второй вариант.

      В целом, вы конечно правы. Описанный способ не избавит от необходимости хранить данные и не сожмёт 40 тб. в сингулярность. С другой стороны разрастание данных - логичное следствие штатной работы системы.

      Вариант закидывать старые партиции с холодными данными на hdd тоже рассматривали. Идея правда хорошая, тем более разные партиции можно вынести на отдельные табличные пространства для размещения на отдельных дисках. Но в нашем случае компании пришлось бы дополнительно закупать отдельно медленные HDD. Мне сказали, что есть быстрые и классные SSD - работайте на них.


  1. vojaganto
    14.10.2024 13:51

    tldr: включили сжатие на уровне бд и уменьшили размер данных в 1.5 раза


  1. ru71an
    14.10.2024 13:51

    Уточните в статье, что HCC возможно только на EXADATA.
    Какой объем данных за год вы пережимаете?
    2 часа это слишком быстро и оптимистично даже с параллельностью 8. По-моему опыту за 2 часа удавалось пережать не так много таблиц. Реализовывали логику на Informatica PowerCenter для еженедельного пережатия данных


    1. FancyStacy
      14.10.2024 13:51

      Зависит от типа данных. Но статья больше похожа на рекламную, это да.