Обновить

Комментарии 7

Примечание переводчика: благодаря Google Lens...

...у вас на картинке из original wide table получился «оригинальный широкий стол», поздравляю.

😁 юмор же тоже должен присутствовать в статье, чтобы не скучно было читать такую стену текста

вам плюсик за внимательность к пасхалкам ✅

Вертикальное партицирование в различных базах данных

Вертикального секционирования не существует - по крайней мере ни в PostgreSQL, ни в MySQL. Существует обычный клиентский слой, который делит таблицу на части, а потом своей логикой изо всех сил пытается обеспечить целостность полученной схемы, с использованием применимых для этой цели возможностей СУБД (внешние ключи и пр.).

Поясню свою мысль на одном из аспектов. До разделения одной широкой таблицы на части запись в обязательном порядке включала в себя абсолютно все поля, причём часть этих полей не допускала пустого значения (NOT NULL), и для таких полей в исходной таблице в любой записи всегда присутствовало значение. Мы разделили таблицу на несколько и связали внешними ключами и клиентской логикой. При этом одна из результирующих таблиц стала "главной", а остальные "дочерними". В дочерние таблицы ушла часть NOT NULL полей. Но внешние ключи, которые являются основой идентификации связности - однонаправленные. А потому не обеспечивают стопроцентно гарантии наличия одной и строго одной (последнее - может обеспечиваться дополнительными ограничениями в дочерней таблице) дочерней записи для каждой главной записи. Соответственно для такой главной записи, у которой отсутствует дочерняя, при сборке исходного, до разделения, состояния, в поле, которое изначально было NOT NULL, нам придётся всё же поместить NULL, потому что дочерней записи с определённым значением не существует. Иными словами, в процессе разделения произошла утрата ограничения, т.е. конечная схема неэквивалентна исходной.

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

По итогу - то, что описывается как вертикальное секционирование, есть не более чем самая обычная перестройка структуры БД. К собственно секционированию никакого отношения не имеющая. Быть и казаться - это не одно и то же.

--------------

Про MongoDB ничего сказать не могу, по этому продукту мои знания для этого совершенно недостаточны.

С теоретической точки зрения вы абсолютно правы: в классических реляционных СУБД (PostgreSQL, MySQL) механизмы, которые мы называем "вертикальным секционированием", по факту реализуются через декомпозицию таблиц (нормализацию), что перекладывает часть ответственности за атомарность создания связей на прикладной уровень или триггерную логику.

Однако в стоит разделить два аспекта:

  1. Терминологический: Почему это называют секционированием, а не просто "перестройкой структуры"? В контексте Highload-систем термин "секционирование" (partitioning) чаще относится к стратегии оптимизации IOPS и памяти. Если мы выносим редко используемые BLOB или тяжелые TEXT поля в отдельную таблицу, чтобы уменьшить размер основной "горячей" таблицы и ускорить Full Table Scan / Index Scan — мы решаем задачу физического размещения данных, а не логического моделирования. Именно поэтому закрепился термин "вертикальное секционирование" — как описание цели действия, а не механизма СУБД.

  2. Проблема эквивалентности схем: Ваше замечание про утрату NOT NULL через связь 1:1 абсолютно обосновано - в классическом SQL действительно нет нативного механизма "Deferred Check" для перекрестных внешних ключей, который бы гарантировал транзакционную вставку в две таблицы как в одну "атомарную" сущность на уровне схемы.

  3. Примечание: В PostgreSQL это частично решается через DEFERRABLE INITIALLY DEFERRED внешние ключи, но это всё равно требует двух операций вставки в рамках одной транзакции.

Вы правы в том, что "нативного" вертикального секционирования (как прозрачного для пользователя механизма, аналогичного горизонтальному декларативному секционированию в PG 11+) в мейнстримных РСУБД практически нет. То, что мы имеем — это "рукотворный" паттерн.

Но называть это "просто перестройкой" тоже не совсем полно, так как цель здесь не нормализация ради чистоты данных, а управление физическим слоем хранения. Мы осознанно меняем "гарантии целостности на уровне схемы" на "производительность и масштабируемость", что является типичным архитектурным компромиссом (trade-off).

Именно поэтому закрепился термин "вертикальное секционирование" — как описание цели действия, а не механизма СУБД

он не закреплялся, нет такого термина. Вертикального секционирования не существует. Причина в том, что читаются тексты на английском, переводятся на аналогиях и partitioning в смысле разделение превращается в секционирование, workload из-за созвучия превращается в highload. В названии статьи правильно написали - "разделение". Изобретенный термин "вертикальное секционирование" если и назвается, то "data segmentation".

Если мы выносим редко используемые BLOB или тяжелые TEXT поля в отдельную таблицу

то это называется TOAST

Но называть это "просто перестройкой" тоже не совсем полно, так как цель здесь не нормализация ради чистоты данных, а управление физическим слоем хранения. Мы осознанно меняем "гарантии целостности на уровне схемы" на "производительность и масштабируемость", что является типичным архитектурным компромиссом (trade-off).

"Не совсем полно" - этого я как-то совсем не понимаю, уж больно смахивает на "слегка беременна".

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

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

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

Верно! В любом случае лично я счёл статью достаточно интересной и полезной, потому и опубликовал её переведённую на русский язык версию.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации