<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>DWH - DataTalks.RU. Data Engineering / DWH / Data Pipeline</title>
	<atom:link href="https://datatalks.ru/category/dwh/feed/" rel="self" type="application/rss+xml" />
	<link>https://datatalks.ru/category/dwh/</link>
	<description>RoadMap для инженера данных. Дорожная карта по инструментам Data Engineer</description>
	<lastBuildDate>Mon, 18 Aug 2025 19:09:19 +0000</lastBuildDate>
	<language>ru-RU</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.0.3</generator>

<image>
	<url>https://datatalks.ru/wp-content/uploads/2024/12/cropped-logo_datatalks-32x32.png</url>
	<title>DWH - DataTalks.RU. Data Engineering / DWH / Data Pipeline</title>
	<link>https://datatalks.ru/category/dwh/</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Требования ACID. BASE модель. CAP теорема</title>
		<link>https://datatalks.ru/acid-base-cap-theorem-for-databases/</link>
					<comments>https://datatalks.ru/acid-base-cap-theorem-for-databases/#respond</comments>
		
		<dc:creator><![CDATA[Data Engineer (Admin)]]></dc:creator>
		<pubDate>Sun, 09 Feb 2025 07:50:06 +0000</pubDate>
				<category><![CDATA[Data Architecture / Data Modeling]]></category>
		<category><![CDATA[DWH]]></category>
		<category><![CDATA[ACID]]></category>
		<category><![CDATA[atomicity]]></category>
		<category><![CDATA[BASE]]></category>
		<category><![CDATA[Basically Available]]></category>
		<category><![CDATA[CAP]]></category>
		<category><![CDATA[CAP Теорема]]></category>
		<category><![CDATA[consistency]]></category>
		<category><![CDATA[durability]]></category>
		<category><![CDATA[Eventually consistent]]></category>
		<category><![CDATA[Soft state]]></category>
		<category><![CDATA[Write-Ahead Logging]]></category>
		<category><![CDATA[Требования ACID]]></category>
		<guid isPermaLink="false">https://datatalks.ru/?p=975</guid>

					<description><![CDATA[<p>Что такое ACID? Представьте, что вы запускаете приложение электронной коммерции. Клиент размещает заказ, и ваша система должна вычесть товар из запасов, списать средства с кредитной карты клиента и зарегистрировать продажу в вашей системе учета — и все это одновременно. Что произойдет, если платеж не пройдет, но ваш счет в инвентаре уже будет уменьшен? Или если [&#8230;]</p>
<p>Сообщение <a href="https://datatalks.ru/acid-base-cap-theorem-for-databases/">Требования ACID. BASE модель. CAP теорема</a> появились сначала на <a href="https://datatalks.ru">DataTalks.RU. Data Engineering / DWH / Data Pipeline</a>.</p>
]]></description>
										<content:encoded><![CDATA[<h1>Что такое ACID?</h1>
<p>Представьте, что вы запускаете приложение электронной коммерции.</p>
<p>Клиент размещает заказ, и ваша система должна вычесть товар из запасов, списать средства с кредитной карты клиента и зарегистрировать продажу в вашей системе учета — и все это одновременно.</p>
<p>Что произойдет, если платеж не пройдет, но ваш счет в инвентаре уже будет уменьшен? Или если ваше приложение зависнет на полпути процесса?</p>
<p>Вот тут-то и вступают в игру транзакции ACID. Они гарантируют, что все шаги в таких критических операциях происходят надежно и последовательно.</p>
<p><strong>ACID (atomicity, consistency, isolation, durability)</strong> — набор требований к транзакционной системе, обеспечивающий наиболее надёжную и предсказуемую её работу — атомарность, согласованность, изоляцию, устойчивость. Сформулированы в конце 1970-х годов Джимом Греем.</p>
<p><a href="https://datatalks.ru/wp-content/uploads/2025/02/acid_properties_in_dbms_details.jpg"><img fetchpriority="high" decoding="async" class="aligncenter size-full wp-image-978" src="https://datatalks.ru/wp-content/uploads/2025/02/acid_properties_in_dbms_details.jpg" alt="" width="1200" height="1202" srcset="https://datatalks.ru/wp-content/uploads/2025/02/acid_properties_in_dbms_details.jpg 1200w, https://datatalks.ru/wp-content/uploads/2025/02/acid_properties_in_dbms_details-300x300.jpg 300w, https://datatalks.ru/wp-content/uploads/2025/02/acid_properties_in_dbms_details-1022x1024.jpg 1022w, https://datatalks.ru/wp-content/uploads/2025/02/acid_properties_in_dbms_details-150x150.jpg 150w, https://datatalks.ru/wp-content/uploads/2025/02/acid_properties_in_dbms_details-768x769.jpg 768w, https://datatalks.ru/wp-content/uploads/2025/02/acid_properties_in_dbms_details-450x451.jpg 450w, https://datatalks.ru/wp-content/uploads/2025/02/acid_properties_in_dbms_details-780x781.jpg 780w" sizes="(max-width: 1200px) 100vw, 1200px" /></a></p>
<p>В этой статье мы подробно рассмотрим значение каждого свойства ACID, почему они важны и как они реализованы в базах данных.</p>
<h2>Что такое транзакция базы данных?</h2>
<p>Транзакция в контексте баз данных — это последовательность из одной или нескольких операций (например, вставка, обновление или удаление записей), которые база данных рассматривает как одно действие. Она либо полностью завершается успешно, либо полностью терпит неудачу, без промежуточных состояний.</p>
<p><strong>Пример: Банковский перевод</strong></p>
<p>Когда вы отправляете деньги другу, происходят две вещи:</p>
<ul>
<li>Деньги списываются с вашего счета.</li>
<li>Деньги зачисляются на их счет.</li>
</ul>
<p>Эти два шага образуют одну транзакцию. Если один из шагов не выполнен, оба отменяются.</p>
<p>Без транзакций базы данных могут оказаться в несогласованном состоянии.</p>
<p><strong>Например:</strong></p>
<ul>
<li><strong>Частичные обновления:</strong> Ваши деньги списываются, но Ваш друг их не получает.</li>
<li><strong>Конфликты:</strong> два человека бронируют последний билет в кино одновременно.</li>
</ul>
<p>Транзакции решают эти проблемы, применяя такие правила, как свойства ACID (атомарность, согласованность, изолированность, долговечность).</p>
<p>Теперь давайте рассмотрим каждое из свойств ACID.</p>
<h2>Atomicity (Атомарность)</h2>
<p>Атомарность гарантирует, что транзакция, включающая несколько операций, выполняется как единая и неделимая единица работы: она либо полностью завершается успешно (фиксируется), либо полностью завершается неудачей (откатывается).</p>
<p>Если какая-либо часть транзакции завершается неудачей, вся транзакция откатывается, а база данных восстанавливается до состояния, в котором она была до начала транзакции.</p>
<p><strong>Пример:</strong> В транзакции денежного перевода, если кредитный шаг не удается, дебетовый шаг не может быть оставлен сам по себе. Это предотвращает несоответствующие состояния, такие как «деньги исчезают» с одного счета, не появляясь на другом.</p>
<p>Атомарность устраняет сложность ручной отмены изменений, если что-то пойдет не так.</p>
<h3>Как базы данных реализуют атомарность</h3>
<p>Базы данных используют два ключевых механизма для обеспечения атомарности.</p>
<p><strong>1. Журналы транзакций (журналы упреждающей записи &#8212; Write-Ahead Log, WAL)</strong></p>
<hr />
<p>У <strong>WAL</strong> есть несколько используемых переводов:</p>
<ul>
<li>Журнал предзаписи</li>
<li>Журнал упреждающей записи</li>
<li>Транзакционный журнал</li>
<li>Упреждающее журналирование</li>
</ul>
<hr />
<p>Реализация:</p>
<ul>
<li>Каждая операция записывается в журнал (WAL), прежде чем она будет применена к фактической таблице базы данных.</li>
<li>В случае сбоя база данных использует этот журнал для отмены незавершенных изменений.</li>
</ul>
<p>Пример:</p>
<p><a href="https://datatalks.ru/wp-content/uploads/2025/02/transaction_log.jpeg"><img decoding="async" class="aligncenter size-full wp-image-1002" src="https://datatalks.ru/wp-content/uploads/2025/02/transaction_log.jpeg" alt="" width="330" height="268" srcset="https://datatalks.ru/wp-content/uploads/2025/02/transaction_log.jpeg 330w, https://datatalks.ru/wp-content/uploads/2025/02/transaction_log-300x244.jpeg 300w" sizes="(max-width: 330px) 100vw, 330px" /></a></p>
<p>После того, как запись WAL безопасно помещена на диск, база данных приступает к изменению страниц в памяти, содержащих строки для учетной записи A и учетной записи B.</p>
<p><strong>В случае успеха операций:</strong></p>
<ul>
<li>База данных отмечает идентификатор транзакции 12345 как зафиксированный в журнале транзакций.</li>
<li>Недавно обновленные балансы для A и B в конечном итоге будут сброшены из памяти в соответствующие файлы данных на диске.</li>
</ul>
<p>Если база данных выходит из строя после записи в журнал, но до полного обновления файлов данных, WAL предоставляет способ восстановления:</p>
<ul>
<li>При перезапуске база данных проверяет WAL.</li>
<li>Видно, что транзакция 12345 была зафиксирована.</li>
<li>Он повторно применяет операции UPDATE, чтобы гарантировать правильность окончательных балансов в файлах данных.</li>
<li>Если транзакция не была зафиксирована (или была помечена как &#171;in progress&#187;) на момент сбоя, база данных откатит эти изменения, используя информацию в журнале, оставив таблицу такой, как будто транзакция никогда не происходила.</li>
</ul>
<p><strong>2. Протоколы фиксации и отката (Commit/Rollback Protocols)</strong></p>
<p>Базы данных предоставляют такие команды <code>BEGIN TRANSACTION</code>, как <code>COMMIT</code>, и <code>ROLLBACK</code>.</p>
<ul>
<li><code>BEGIN TRANSACTION</code> — начало транзакции.</li>
<li><code>COMMIT</code> — фиксация изменений.</li>
<li><code>ROLLBACK</code> — откат изменений.</li>
</ul>
<p>Любые изменения, внесенные между BEGIN TRANSACTION и COMMIT считаются «выполняемыми» и не будут применены навсегда, если транзакция не будет успешно зафиксирована.</p>
<p>Если какой-либо шаг не выполнен или вы явно указали ROLLBACK, все изменения, внесенные с момента начала транзакции, будут отменены.</p>
<p><strong>Пример:</strong></p>
<p><a href="https://datatalks.ru/wp-content/uploads/2025/02/begin_transaction_commit.jpeg"><img decoding="async" class="aligncenter size-full wp-image-1004" src="https://datatalks.ru/wp-content/uploads/2025/02/begin_transaction_commit.jpeg" alt="" width="612" height="401" srcset="https://datatalks.ru/wp-content/uploads/2025/02/begin_transaction_commit.jpeg 612w, https://datatalks.ru/wp-content/uploads/2025/02/begin_transaction_commit-300x197.jpeg 300w, https://datatalks.ru/wp-content/uploads/2025/02/begin_transaction_commit-450x295.jpeg 450w" sizes="(max-width: 612px) 100vw, 612px" /></a></p>
<h2>Consistency (Согласованность)</h2>
<p>Согласованность в контексте ACID-транзакций гарантирует, что любая транзакция переводит базу данных из одного допустимого состояния в другое допустимое состояние — никогда не оставляя её в некорректном или «невалидном» состоянии.</p>
<p>Это означает, что все ограничения целостности данных, такие как ограничения первичного ключа (отсутствие дублирующихся идентификаторов), ограничения внешнего ключа (связанные записи должны существовать в родительских таблицах) и ограничения проверки (возраст не может быть отрицательным), соблюдаются до и после выполнения транзакции.</p>
<p>Если транзакция пытается нарушить эти правила, она не будет зафиксирована, и база данных вернётся в предыдущее состояние.</p>
<p>Пример:</p>
<p>В базе данных электронной коммерции есть две таблицы:</p>
<ul>
<li>products (со столбцами: product_id, stock_quantity, и т.д.)</li>
<li>orders (со столбцами: order_id, product_id, quantity, и т.д.)</li>
<li>Ограничение: Нельзя разместить заказ на товар, если запрашиваемое количество (quantity) превышает stock_quantity в таблице products.</li>
</ul>
<p>Transaction Flow (Последовательность транзакции):</p>
<p><a href="https://datatalks.ru/wp-content/uploads/2025/02/transaction_flow_begin.jpeg"><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-1007" src="https://datatalks.ru/wp-content/uploads/2025/02/transaction_flow_begin.jpeg" alt="" width="632" height="333" srcset="https://datatalks.ru/wp-content/uploads/2025/02/transaction_flow_begin.jpeg 632w, https://datatalks.ru/wp-content/uploads/2025/02/transaction_flow_begin-300x158.jpeg 300w, https://datatalks.ru/wp-content/uploads/2025/02/transaction_flow_begin-450x237.jpeg 450w" sizes="(max-width: 632px) 100vw, 632px" /></a></p>
<p>Если stock_quantity товара было 8 (меньше, чем количество, которое мы пытаемся заказать), база данных обнаружит, что новое значение будет -2, что нарушает правило согласованности (значение не должно становиться отрицательным).</p>
<p>Транзакция завершится с ошибкой или вызовет откат (rollback), предотвращая попадание базы данных в некорректное состояние.</p>
<h3>Как реализовать согласованность?</h3>
<p><strong>Ограничения схемы базы данных</strong></p>
<ul>
<li>Ограничения NOT NULL, UNIQUE, PRIMARY KEY, FOREIGN KEY, CHECK и другие определения схемы предотвращают ввод недопустимых данных.</li>
</ul>
<p><strong>Триггеры и хранимые процедуры</strong></p>
<ul>
<li>Триггеры могут автоматически проверять дополнительные правила при вставке, обновлении или удалении строк.</li>
<li>Хранимые процедуры могут содержать логику для проверки данных перед фиксацией изменений.</li>
</ul>
<p><strong>Защита на уровне приложения</strong></p>
<ul>
<li>В то время как база данных обеспечивает соблюдение ограничений на более низком уровне, приложения часто добавляют дополнительные проверки, например, для обеспечения соблюдения бизнес-правил или проверки данных еще до того, как они попадут на уровень базы данных.</li>
</ul>
<h2>Isolation (Изоляция)</h2>
<p>Изоляция гарантирует, что одновременно выполняющиеся транзакции не вмешиваются в промежуточные состояния друг друга.</p>
<p>По сути, пока транзакция выполняется, её обновления (или промежуточные данные) остаются невидимыми для других параллельно выполняющихся транзакций, создавая иллюзию того, что каждая транзакция выполняется последовательно, одна за другой.</p>
<p>Без изоляции две или более транзакции могли бы читать и записывать частичные или незавершённые данные друг от друга, что привело бы к некорректным или несогласованным результатам.</p>
<p>Благодаря изоляции разработчики могут более надёжно прогнозировать, как изменения данных будут видны другим транзакциям.</p>
<h3>Аномалии конкурентного доступа / Аномалии параллелизма</h3>
<p>Чтобы понять, как работает изоляция, полезно рассмотреть, какие проблемы могут возникнуть при её отсутствии. Основные аномалии конкурентного доступа включают:</p>
<p><strong>Грязное чтение (Dirty Read)</strong></p>
<ul>
<li>Транзакция A читает данные, которые были изменены, но ещё не зафиксированы транзакцией B.</li>
<li>Если затем транзакция B выполняет откат (ROLLBACK), транзакция A окажется с недействительным или «грязным» значением, которое фактически никогда не существовало в зафиксированном состоянии.</li>
</ul>
<p><strong>Неповторяемое чтение (Non-Repeatable Read)</strong></p>
<ul>
<li>Транзакция A считывает одни и те же строки несколько раз во время своего выполнения, но видит разные данные, поскольку другая транзакция обновила или удалила эти строки между чтениями A.</li>
</ul>
<p><strong>Фантомное чтение (Phantom Read)</strong></p>
<ul>
<li>Транзакция A несколько раз читает одну и ту же строку (или строки) во время выполнения.</li>
<li>Между этими чтениями другая транзакция изменяет или удаляет соответствующие строки.</li>
<li>В результате транзакция A видит разные значения при повторных чтениях одной и той же строки.</li>
</ul>
<h3>Уровни изоляции</h3>
<p>Базы данных обычно позволяют выбрать уровень изоляции, который обеспечивает баланс между корректностью данных и производительностью.</p>
<p>Более высокие уровни изоляции обеспечивают более высокую согласованность данных, но могут снизить производительность системы за счет увеличения времени ожидания транзакций.</p>
<p>Давайте рассмотрим четыре распространенных уровня изоляции.</p>
<h4><strong>Read Uncommitted (Чтение неподтверждённых данных)</strong></h4>
<p>Разрешает грязное чтение; транзакции могут видеть незафиксированные изменения.</p>
<p>Используется редко, так как может привести к серьезным аномалиям.</p>
<p><a href="https://datatalks.ru/wp-content/uploads/2025/02/transactions.jpeg"><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-1008" src="https://datatalks.ru/wp-content/uploads/2025/02/transactions.jpeg" alt="" width="581" height="112" srcset="https://datatalks.ru/wp-content/uploads/2025/02/transactions.jpeg 581w, https://datatalks.ru/wp-content/uploads/2025/02/transactions-300x58.jpeg 300w, https://datatalks.ru/wp-content/uploads/2025/02/transactions-450x87.jpeg 450w" sizes="(max-width: 581px) 100vw, 581px" /></a></p>
<h4><strong>Read Committed (Чтение подтверждённых данных)</strong></h4>
<p>Транзакция видит только те данные, которые были зафиксированы на момент чтения.</p>
<p>Предотвращает «грязное» чтение, однако неповторяющиеся чтения и фантомные чтения все еще могут иметь место.</p>
<p><a href="https://datatalks.ru/wp-content/uploads/2025/02/transactions_2.jpeg"><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-1009" src="https://datatalks.ru/wp-content/uploads/2025/02/transactions_2.jpeg" alt="" width="400" height="86" srcset="https://datatalks.ru/wp-content/uploads/2025/02/transactions_2.jpeg 400w, https://datatalks.ru/wp-content/uploads/2025/02/transactions_2-300x65.jpeg 300w" sizes="(max-width: 400px) 100vw, 400px" /></a></p>
<h4><strong>Repeatable Read (Повторяемое чтение)</strong></h4>
<p>Гарантирует, что при многократном чтении одних и тех же строк в рамках транзакции вы получите одни и те же значения (если только вы явно не измените их).</p>
<p>Предотвращает грязное чтение и неповторяющееся чтение, но фантомное чтение все равно может произойти (в зависимости от ядра базы данных).</p>
<p><a href="https://datatalks.ru/wp-content/uploads/2025/02/transactions_3.jpeg"><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-1010" src="https://datatalks.ru/wp-content/uploads/2025/02/transactions_3.jpeg" alt="" width="477" height="82" srcset="https://datatalks.ru/wp-content/uploads/2025/02/transactions_3.jpeg 477w, https://datatalks.ru/wp-content/uploads/2025/02/transactions_3-300x52.jpeg 300w, https://datatalks.ru/wp-content/uploads/2025/02/transactions_3-450x77.jpeg 450w" sizes="(max-width: 477px) 100vw, 477px" /></a></p>
<h4><strong>Serializable (Сериализуемость)</strong></h4>
<p>Самый высокий уровень изоляции, при котором все транзакции происходят последовательно, по одной за раз.</p>
<p>Предотвращает грязное чтение, неповторяющееся чтение и фантомное чтение.</p>
<p>Самый затратный с точки зрения производительности и параллелизма, поскольку может потребоваться больше блокировок или больше проверок конфликтов.</p>
<p><a href="https://datatalks.ru/wp-content/uploads/2025/02/transactions_4.jpeg"><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-1013" src="https://datatalks.ru/wp-content/uploads/2025/02/transactions_4.jpeg" alt="" width="508" height="152" srcset="https://datatalks.ru/wp-content/uploads/2025/02/transactions_4.jpeg 508w, https://datatalks.ru/wp-content/uploads/2025/02/transactions_4-300x90.jpeg 300w, https://datatalks.ru/wp-content/uploads/2025/02/transactions_4-450x135.jpeg 450w" sizes="(max-width: 508px) 100vw, 508px" /></a></p>
<h3>Как базы данных обеспечивают изоляцию</h3>
<h4><strong>Блокировки (Locking)</strong></h4>
<ul>
<li>Пессимистичный контроль конкурентности (Pessimistic Concurrency Control)</li>
<li>Строки или таблицы блокируются, чтобы никакая другая транзакция не могла их читать или изменять, пока блокировка не будет снята.</li>
<li>Может привести к блокировке (blocking) или взаимоблокировке (deadlock), если несколько транзакций конкурируют за одни и те же блокировки.</li>
</ul>
<h4><strong>MVCC (Многоверсионное управление конкурентным доступом — Multi-Version Concurrency Control)</strong></h4>
<ul>
<li>Оптимистичный контроль конкурентности (Optimistic Concurrency Control)</li>
<li>Вместо блокировки чтения база данных хранит несколько версий одной и той же строки.</li>
<li>Читающие транзакции видят согласованный снимок данных (как если бы они смотрели на состояние в определённый момент времени), а записывающие транзакции создают новую версию строки при обновлении.</li>
<li>Этот подход уменьшает конфликты блокировок, но требует тщательного управления версиями строк и их очистки (например, механизма vacuum в PostgreSQL).</li>
</ul>
<h4><strong>Изоляция снапшотов (Snapshot Isolation)</strong></h4>
<ul>
<li>Вариант MVCC, при котором каждая транзакция видит данные в том виде, в каком они были в начале её выполнения (или на согласованной точке во времени).</li>
<li>Предотвращает грязные чтения (Dirty Reads) и неповторяемые чтения (Non-Repeatable Reads).</li>
<li>Фантомные чтения (Phantom Reads) всё ещё возможны, если уровень изоляции не установлен в Serializable.</li>
</ul>
<h2>Durability (Устойчивость/Надежность/Долговечность)</h2>
<p>Надежность гарантирует, что после завершения транзакции внесенные изменения сохранятся даже в случае сбоев питания, сбоев или других катастрофических событий.</p>
<p>Другими словами, как только транзакция завершается, данные фиксируются навсегда и не могут просто исчезнуть.</p>
<h3>Как базы данных обеспечивают долговечность</h3>
<h4><strong>Журнал транзакций (Write-Ahead Logging, WAL)</strong></h4>
<p>Большинство реляционных баз данных используют журнал упреждающей записи (WAL) для сохранения изменений до их записи в основные файлы данных:</p>
<ul>
<li><strong>Write Changes to WAL (Запись изменений в WAL):</strong> предполагаемые операции (обновления, вставки, удаления) записываются в WAL на долговременном носителе (диске).</li>
<li><strong>Commit the Transaction (Зафиксировать транзакцию):</strong> как только запись WAL будет безопасно сохранена, база данных может пометить транзакцию как зафиксированную.</li>
<li><strong>Apply Changes to Main Data Files (Применить изменения к основным файлам данных):</strong> обновленные данные в конечном итоге записываются в основные файлы — возможно, сначала в память, а затем сбрасываются на диск.</li>
</ul>
<p>В случае сбоя базы данных во время восстановления она использует WAL :</p>
<ul>
<li><strong>Redo (Повторить):</strong> любые зафиксированные транзакции, еще не отраженные в основных файлах, применяются повторно.</li>
<li><strong>Undo (Отменить):</strong> все незавершенные (незафиксированные) транзакции откатываются для сохранения согласованности базы данных.</li>
</ul>
<h4><strong>Репликация / Избыточность (Replication / Redundancy)</strong></h4>
<p>Помимо WAL, многие системы используют репликацию, чтобы гарантировать сохранность данных даже в случае отказа оборудования или всего центра обработки данных.</p>
<ul>
<li><strong>Синхронная репликация:</strong> записи немедленно копируются на несколько узлов или центров обработки данных. Транзакция помечается как зафиксированная, только если первичный узел и по крайней мере одна реплика подтверждают, что она безопасно сохранена.</li>
<li><strong>Асинхронная репликация:</strong> изменения в конечном итоге синхронизируются с другими узлами, но существует (небольшое) окно, в котором может произойти потеря данных, если основной узел выйдет из строя до обновления реплики.</li>
</ul>
<h4><strong>Backups (Резервные копии)</strong></h4>
<p>Регулярные резервные копии обеспечивают сеть безопасности за пределами журналов и репликации. В случае серьезного повреждения, человеческой ошибки или катастрофического сбоя:</p>
<ul>
<li><strong>Полные резервные копии:</strong> сохранение всей базы данных на определенный момент времени.</li>
<li><strong>Инкрементное/дифференциальное резервное копирование:</strong> сохранение изменений с момента последнего резервного копирования для более быстрого и частого резервного копирования.</li>
<li><strong>Внешнее хранение:</strong> обеспечивает сохранность резервных копий в случае локальных сбоев, позволяя восстанавливать данные даже в случае повреждения оборудования.</li>
</ul>
<h2>Сравнительная таблица требований ACID в различных транзакционных СУБД</h2>


<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>База данных</th><th>Atomicity (Атомарность)</th><th>Consistency (Согласованность)</th><th>Isolation (Изоляция)</th><th>Durability (Надёжность)</th></tr></thead><tbody><tr><td>MSSQL</td><td>Использует журналы транзакций (Write-Ahead Logging, WAL), транзакции полностью атомарны</td><td>Гарантирует согласованность через строгие ограничения и триггеры</td><td>Поддерживает уровни изоляции: Read Uncommitted, Read Committed, Repeatable Read, Serializable, Snapshot</td><td>Журнал транзакций обеспечивает сохранность данных даже при сбоях</td></tr><tr><td>PostgreSQL</td><td>Использует WAL для атомарности транзакций</td><td>Поддерживает строгие ограничения целостности</td><td>MVCC (многоверсионность), уровни изоляции: Read Committed, Repeatable Read, Serializable</td><td>WAL обеспечивает надежность, данные сохраняются даже при сбое</td></tr><tr><td>MySQL (InnoDB)</td><td>InnoDB использует двухфазную фиксацию (2PC) и WAL</td><td>Ограничения целостности и внешние ключи поддерживаются</td><td>Поддержка уровней изоляции: Read Uncommitted, Read Committed, Repeatable Read, Serializable</td><td>Использует WAL, поддерживает автоматическое восстановление</td></tr><tr><td>Oracle</td><td>Использует механизмы undo/redo для атомарности</td><td>Строгая согласованность через ограничения и триггеры</td><td>Использует MVCC, уровни изоляции: Read Committed, Serializable</td><td>Надежное восстановление через redo-логи</td></tr><tr><td>IBM Db2</td><td>Использует WAL, гарантирует атомарность</td><td>Ограничения целостности, поддержка ACID-совместимых операций</td><td>Поддерживает уровни изоляции: Cursor Stability (CS), Repeatable Read (RR), Serializable</td><td>Надежность обеспечивается за счет WAL и резервного копирования</td></tr><tr><td>MariaDB (InnoDB, Aria)</td><td>InnoDB аналогичен MySQL, Aria поддерживает транзакции с журналированием</td><td>Поддержка ограничений целостности</td><td>MVCC (InnoDB), разные уровни изоляции</td><td>Журнал транзакций и восстановление</td></tr><tr><td>Firebird</td><td>Использует журнал изменений и механизм Undo</td><td>Строгая целостность данных</td><td>Поддерживает Snapshot Isolation, Read Committed, Serializable</td><td>Журнал транзакций защищает данные</td></tr><tr><td>SQLite</td><td>Использует механизм журнала транзакций (WAL)</td><td>Ограниченная поддержка ограничений целостности</td><td>Поддерживает уровни: Read Uncommitted, Serializable</td><td>Данные сохраняются в файле базы данных, но надежность зависит от настроек</td></tr></tbody></table></figure>


<h3>Пояснение по некоторой терминологии СУБД</h3>
<p><strong>Write-Ahead Logging (WAL) &#8212; Журнал опережающей записи</strong> – это метод, при котором изменения записываются сначала в журнал (лог), а затем применяются к основной базе данных. Это обеспечивает надежность транзакций, так как в случае сбоя можно восстановить данные из журнала.</p>
<p><strong>Уровни изоляции транзакций</strong></p>
<p><em>Чем выше уровень, тем меньше конкуренция, но выше задержки и блокировки</em></p>
<ul>
<li><strong>Cursor Stability (CS)</strong> – промежуточный уровень изоляции в IBM Db2, удерживает блокировку только на текущей строке, а не на всей транзакции.</li>
<li><strong>Read Uncommitted</strong> – самый низкий уровень, позволяет читать &#171;грязные&#187; (незафиксированные) данные других транзакций.</li>
<li><strong>Read Committed</strong> – транзакция видит только зафиксированные данные, но могут появляться &#171;фантомные&#187; чтения (изменения других транзакций).</li>
<li><strong>Repeatable Read</strong> – предотвращает &#171;фантомные&#187; чтения, но другие транзакции могут добавлять новые строки.</li>
<li><strong>Serializable</strong> – самый строгий уровень, транзакции выполняются последовательно, исключая все виды аномалий.</li>
<li><strong>Snapshot</strong> – транзакция видит данные в момент начала работы (используется в MVCC), обеспечивая изоляцию без блокировок.</li>
</ul>
<p><strong>MVCC (Multi-Version Concurrency Control)</strong></p>
<p>Многоверсионное управление конкурентным доступом – механизм, позволяющий транзакциям работать с разными версиями данных без блокировок. Это улучшает производительность и снижает конфликты.</p>
<p><strong>Двухфазная фиксация (2PC &#8212; Two-Phase Commit)</strong></p>
<p>Протокол, используемый при распределённых транзакциях. Он работает в два шага:</p>
<ul>
<li><strong>Подготовка</strong> – все узлы подтверждают готовность зафиксировать транзакцию.</li>
<li><strong>Фиксация</strong> – если все согласны, транзакция фиксируется. Если хоть один отказывает, транзакция откатывается.</li>
</ul>
<p><strong>Механизмы undo/redo для атомарности</strong></p>
<ul>
<li><strong>Undo (отмена)</strong> – используется для отката изменений, если транзакция прервана.</li>
<li><strong>Redo (повторное выполнение)</strong> – применяется для восстановления завершённых транзакций после сбоя.</li>
</ul>
<p><strong>Redo-логи</strong></p>
<p>Логи, содержащие информацию о зафиксированных транзакциях, чтобы можно было повторить изменения после сбоя системы.</p>
<p><strong>Журнал транзакций и восстановление</strong></p>
<p>Файл или структура данных в базе, записывающая все операции изменения данных. В случае сбоя система может восстановить последнюю корректную версию базы, используя этот журнал.</p>
<h1>BASE-модель для NoSQL баз данных</h1>
<p>В отличие от <strong>ACID-модели</strong>, которая ориентирована на <span style="color: #ff6600;"><strong>строгую согласованность</strong></span>, <strong>BASE (Basically Available, Soft state, Eventually consistent)</strong> подходит для распределённых NoSQL баз данных, где важнее доступность и масштабируемость.</p>
<p>Во второй половине 2000-х годов сформулирован подход к построению распределённых систем, в которых требования целостности и доступности выполнены не в полной мере, названый акронимом BASE (Basically Available, Soft-state, Eventually consistent — базовая доступность, неустойчивое состояние, согласованность в конечном счёте), при этом такой подход напрямую противопоставляется ACID.</p>
<p><strong>Под базовой доступностью</strong> подразумевается такой подход к проектированию приложения, чтобы сбой в некоторых узлах приводил к отказу в обслуживании только для незначительной части сессий при сохранении доступности в большинстве случаев.</p>
<p><strong>Неустойчивое состояние</strong> подразумевает возможность жертвовать долговременным хранением состояния сессий (таких как промежуточные результаты выборок, информация о навигации, контексте), при этом концентрируясь на фиксации обновлений только критичных операций.</p>
<p><strong>Согласованности</strong> в конечном счёте, трактующейся как возможность противоречивости данных в некоторых случаях, но при обеспечении согласования в практически обозримое время, посвящено значительное количество самостоятельных исследований.</p>
<h2><strong>BASE: <span style="color: #ff6600;">Basically Available</span> / <span style="color: #003366;">Soft state</span> / <span style="color: #339966;">Eventually consistent</span></strong></h2>
<p><strong>Basically Available (Базовая доступность)</strong></p>
<ul>
<li>Система гарантирует доступность данных даже в случае частичных отказов.</li>
<li>Данные могут быть не полностью согласованными, но запросы не блокируются.</li>
<li>Например, если один сервер недоступен, другой всё равно может выдать старую версию данных.</li>
</ul>
<p><strong>Soft state (Гибкое состояние)</strong></p>
<ul>
<li>Состояние системы может изменяться со временем даже без новых запросов.</li>
<li>Это значит, что данные в разных узлах могут временно отличаться из-за асинхронной репликации.</li>
<li>Например, если запись обновилась на одном сервере, изменения могут дойти до других с задержкой.</li>
</ul>
<p><strong>Eventually consistent (Окончательная согласованность)</strong></p>
<ul>
<li>Система со временем достигает согласованности, но не сразу.</li>
<li>Это позволяет масштабировать базы данных и повышать отказоустойчивость.</li>
<li>Например, в DynamoDB или Cassandra данные могут быть сначала разными на разных узлах, но через некоторое время синхронизируются.</li>
</ul>
<h2>Когда выбирают BASE вместо ACID?</h2>
<p><strong>BASE подходит, когда:</strong></p>
<ul>
<li>Важнее скорость и отказоустойчивость, чем мгновенная согласованность.</li>
<li>Данные могут быть временно несогласованными, но постепенно синхронизируются.</li>
<li>Используются распределённые NoSQL базы (Cassandra, DynamoDB, Riak, CouchDB).</li>
</ul>
<p>В отличие от ACID, BASE жертвует строгой целостностью ради масштабируемости и высокой доступности.</p>
<h2>Примеры популярных NoSQL баз данных</h2>
<h3>Документные базы данных (хранят данные в виде JSON, BSON, XML)</h3>
<ul>
<li><strong>MongoDB</strong> – самая популярная документная NoSQL БД, поддерживает гибкие схемы данных.</li>
<li><strong>CouchDB</strong> – использует JSON-документы и репликацию, оптимизирована для распределённых систем.</li>
<li><strong>Firebase Firestore</strong> – облачная NoSQL база от Google, активно используется в мобильных и веб-приложениях.</li>
</ul>
<h3>Ключ-значение (Key-Value) базы данных (быстрый доступ по ключу)</h3>
<ul>
<li><strong>Redis</strong> – сверхбыстрая in-memory NoSQL база, часто используется для кеширования.</li>
<li><strong>Amazon DynamoDB</strong> – облачная NoSQL база от AWS, хорошо масштабируется.</li>
<li><strong>Riak KV</strong> – распределённая база данных с высокой отказоустойчивостью.</li>
</ul>
<h3>Графовые базы данных (оптимизированы для работы с графами и связями)</h3>
<ul>
<li><strong>Neo4j</strong> – самая популярная графовая база, используется в социальных сетях, рекомендательных системах.</li>
<li><strong>ArangoDB</strong> – мультипарадигменная база (графы + документы + ключ-значение).<br />Amazon Neptune – облачная графовая БД от AWS, поддерживает Gremlin и SPARQL.</li>
</ul>
<h3>Колонночные базы данных (работают с огромными объёмами данных, оптимизированы для аналитики)</h3>
<ul>
<li><strong>Apache Cassandra</strong> – масштабируемая распределённая NoSQL БД от Facebook.</li>
<li><strong>HBase</strong> – построена на Hadoop, подходит для Big Data.</li>
<li><strong>Google Bigtable</strong> – облачная колонночная база от Google.</li>
</ul>
<h3>Time-Series базы данных (оптимизированы для работы с временными рядами)</h3>
<ul>
<li><strong>InfluxDB</strong> – популярная база для сбора и анализа данных о временных рядах (например, IoT-устройства, логи).</li>
<li><strong>TimescaleDB</strong> – расширение PostgreSQL для работы с временными рядами.</li>
<li><strong>OpenTSDB</strong> – работает поверх HBase, предназначена для хранения больших объёмов временных данных.</li>
</ul>
<h2>Как принцип BASE обеспечивается в СУБД?</h2>
<p>Вместо строгой ACID-согласованности базы BASE обеспечивают &#171;размытую&#187; согласованность, используя асинхронную репликацию, механизмы конфликтного разрешения и компромиссные модели консистентности.</p>
<p>Ниже будут рассмотрены некоторые из приемов, которые обеспечивают тот или иной пункт модели BASE.</p>
<h3><strong>Basically Available (Базовая доступность)</strong></h3>
<p><em><strong>Базовая доступность</strong> означает, что база данных должна быть доступна одновременно для всех пользователей в любое время. Пользователю не нужно ждать, пока завершатся другие транзакции, прежде чем обновлять запись. Например, в случае внезапного роста трафика система электронной коммерции может отдавать предпочтение выдаче списков и приему заказов. Не страшно, если обновление количества запасов будет выполнено с небольшой задержкой, зато пользователи продолжают покупать товары.</em></p>
<hr />
<p>Даже если часть системы выходит из строя, база продолжает работать.</p>
<ul>
<li><strong>Репликация данных</strong> – копии хранятся на нескольких узлах.</li>
<li><strong>Eventual Consistency</strong> – данные синхронизируются позже, но система не блокируется.</li>
<li><strong>Шардирование (разделение данных)</strong> – нагрузка делится на множество узлов.</li>
</ul>
<p>Пример:</p>
<ul>
<li>Cassandra или DynamoDB используют quorum-репликацию, где большинство узлов должны подтвердить запись.</li>
<li>Redis Cluster распределяет данные по узлам, гарантируя высокую доступность.</li>
</ul>
<h3><strong>Soft State (Гибкое состояние)</strong></h3>
<p><em><strong>Гибкое/Мягкое состояние</strong> здесь означает, что любые данные могут находиться в промежуточных или временных состояниях и в некоторый момент изменяться «сами по себе», без внешних событий или поступления новых данных. Эта концепция отражает неопределенное состояние записи, которую обновляют несколько приложений одновременно. Значение такой записи будет окончательно определено только после завершения всех транзакций. Например, если пользователи редактируют сообщение в социальной сети, внесенные ими изменения могут быть не сразу видны другим пользователям. Через некоторое время система учтет все внесенные изменения, и произойдет обновление сообщения, хотя ни один пользователь его не инициировал.</em></p>
<hr />
<p>Система может изменяться даже без новых транзакций.</p>
<ul>
<li><strong>Асинхронная репликация</strong> – данные распространяются между узлами не сразу, а с задержкой.</li>
<li><strong>Кэширование</strong> – данные могут храниться в распределённых узлах и устаревать.</li>
<li><strong>Механизмы разруливания конфликтов</strong> – например, last-write-wins (LWW), CRDT (Conflict-Free Replicated Data Types).</li>
</ul>
<p>Пример:</p>
<ul>
<li>В Riak можно настроить стратегию разрешения конфликтов – брать последнее изменение или объединять данные.</li>
<li>В MongoDB при репликации вторичные узлы могут временно содержать устаревшие данные.</li>
</ul>
<h3><strong>Eventually Consistent (Окончательная согласованность)</strong></h3>
<p><em><strong>Окончательная согласованность</strong> означает, что запись достигнет согласованности не сразу, а после завершения всех одновременных обновлений. После этого все приложения, запрашивающие эту запись, увидят одно и то же значение. Давайте рассмотрим в качестве примера распределенную систему редактирования документов, в которой несколько пользователей могут одновременно редактировать документ. Если пользователь A и пользователь B одновременно редактируют один и тот же раздел документа, их локальные копии могут временно различаться, пока не завершатся процессы распространения и синхронизации. Однако со временем, «в конечном счете», система достигает согласованности, распространяя и объединяя все изменения от разных пользователей.</em></p>
<hr />
<p>Данные на всех узлах рано или поздно становятся одинаковыми.</p>
<ul>
<li>Гибкие уровни согласованности – например, &#171;читаем свежие данные, если возможно&#187;.</li>
<li>Механизмы Gossip Protocol – узлы обмениваются информацией о последних изменениях.</li>
<li>Read Repair – если запрос вернул устаревшие данные, база может их обновить в фоновом режиме.</li>
</ul>
<p>Пример:</p>
<ul>
<li>Cassandra использует hinted handoff (хранит &#171;подсказки&#187; для недоступных узлов и передаёт их позже).</li>
<li>DynamoDB применяет vector clocks (временные метки для согласования версий данных).</li>
</ul>
<h1>Краткое описание различий между ACID и BASE</h1>
<p><a href="https://datatalks.ru/wp-content/uploads/2025/02/acid_vs_base.jpeg"><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-1026" src="https://datatalks.ru/wp-content/uploads/2025/02/acid_vs_base.jpeg" alt="" width="1078" height="376" srcset="https://datatalks.ru/wp-content/uploads/2025/02/acid_vs_base.jpeg 1078w, https://datatalks.ru/wp-content/uploads/2025/02/acid_vs_base-300x105.jpeg 300w, https://datatalks.ru/wp-content/uploads/2025/02/acid_vs_base-1024x357.jpeg 1024w, https://datatalks.ru/wp-content/uploads/2025/02/acid_vs_base-768x268.jpeg 768w, https://datatalks.ru/wp-content/uploads/2025/02/acid_vs_base-450x157.jpeg 450w, https://datatalks.ru/wp-content/uploads/2025/02/acid_vs_base-780x272.jpeg 780w" sizes="(max-width: 1078px) 100vw, 1078px" /></a></p>
<h1>Теорема CAP (Consistency, Availability, Partition Tolerance)</h1>
<p>В мире распределённых баз данных ключевую роль играет теорема<strong> CAP (Consistency, Availability, Partition Tolerance)</strong>, предложенная <strong>Эриком Брюэром (Eric Brewer)</strong> в 2000 году.</p>
<p>Теорема CAP в информатике гласит, что распределенное хранилище данных не может предоставить более двух из трех следующих гарантий:</p>
<ul>
<li><strong>C – Consistency (Согласованность):</strong> каждое чтение получает самую последнюю запись или ошибку. Все узлы видят одни и те же данные в одно и то же время.</li>
<li><strong>A – Availability (Доступность):</strong> каждый запрос получает ответ (без ошибок), без гарантии, что он содержит самую последнюю запись. Система отвечает на запросы даже при сбоях, но может выдавать устаревшие данные.</li>
<li><strong>P – Partition Tolerance (Устойчивость к разделению сети):</strong> система продолжает работать, несмотря на произвольное количество сообщений, удаленных (или задержанных) сетью между узлами. Система продолжает работать, даже если сеть между узлами разорвана.</li>
</ul>
<p><strong>Главный вывод теоремы CAP:</strong> в случае сетевых проблем (P) база данных должна выбрать между строгой согласованностью (C) или доступностью (A).</p>
<p><a href="https://datatalks.ru/wp-content/uploads/2025/02/CAP_Theorem_graph.jpeg"><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-997" src="https://datatalks.ru/wp-content/uploads/2025/02/CAP_Theorem_graph.jpeg" alt="" width="1946" height="720" srcset="https://datatalks.ru/wp-content/uploads/2025/02/CAP_Theorem_graph.jpeg 1946w, https://datatalks.ru/wp-content/uploads/2025/02/CAP_Theorem_graph-300x111.jpeg 300w, https://datatalks.ru/wp-content/uploads/2025/02/CAP_Theorem_graph-1024x379.jpeg 1024w, https://datatalks.ru/wp-content/uploads/2025/02/CAP_Theorem_graph-768x284.jpeg 768w, https://datatalks.ru/wp-content/uploads/2025/02/CAP_Theorem_graph-1536x568.jpeg 1536w, https://datatalks.ru/wp-content/uploads/2025/02/CAP_Theorem_graph-450x166.jpeg 450w, https://datatalks.ru/wp-content/uploads/2025/02/CAP_Theorem_graph-780x289.jpeg 780w, https://datatalks.ru/wp-content/uploads/2025/02/CAP_Theorem_graph-1600x592.jpeg 1600w" sizes="(max-width: 1946px) 100vw, 1946px" /></a></p>
<hr />
<p><strong>CAP теорема указывает, что распределенная система может иметь максимум два свойства из трех одновременно:</strong></p>
<ol>
<li><strong>Согласованность (атомарность)</strong> &#8212; Каждая операция чтения, должна возвращать значение, установленное в последней операции записи: то есть у каждого узла есть актуальные данные о определенном объекте (или данные во всех узлах не противоречат друг другу).</li>
<li><strong>Доступность</strong> &#8212; Каждый запрос, полученный исправным узлом, влечет за собой ответ. Изначально было что: &#171;почти все запросы должны получать ответы&#187;. Отсутствие ответа &#8212; неответ по таймауту, и все ошибки формата &#171;сервер занят&#187;.</li>
<li><strong>Устойчивость к распределению:</strong> Кластер сохраняет работоспособность при условии потери произвольного количества сообщений, посылаемых между узлами сети. Распределение означает, что все пакеты от узлов одной партиции не доходят до узлов другой партиции.</li>
</ol>
<p><em>В 2002 году Сет Джилберт и Нэнси Линч из Массачусетского технологического института подобрали формальные модели асинхронных и синхронных распределённых вычислений, в рамках которых показано выполнение теоремы CAP в условиях отсутствия синхронизации (общих часов) у узлов распределённой системы и принципиальную возможность компромисса в частично синхронных системах. В этой работе «согласованность» в смысле теоремы CAP соотнесена с выполнением первых двух требований ACID — атомарности и согласованности. В дальнейшем, многие практики ссылались на данную работу как на доказательство теоремы CAP.</em></p>
<h2>Как теорема CAP влияет на выбор баз данных?</h2>
<p><a href="https://datatalks.ru/wp-content/uploads/2025/02/cap_theorem_databases.jpeg" target="_blank" rel="noopener"><img loading="lazy" decoding="async" class="aligncenter wp-image-993 size-full" src="https://datatalks.ru/wp-content/uploads/2025/02/cap_theorem_databases.jpeg" alt="" width="1155" height="590" srcset="https://datatalks.ru/wp-content/uploads/2025/02/cap_theorem_databases.jpeg 1155w, https://datatalks.ru/wp-content/uploads/2025/02/cap_theorem_databases-300x153.jpeg 300w, https://datatalks.ru/wp-content/uploads/2025/02/cap_theorem_databases-1024x523.jpeg 1024w, https://datatalks.ru/wp-content/uploads/2025/02/cap_theorem_databases-768x392.jpeg 768w, https://datatalks.ru/wp-content/uploads/2025/02/cap_theorem_databases-450x230.jpeg 450w, https://datatalks.ru/wp-content/uploads/2025/02/cap_theorem_databases-780x398.jpeg 780w" sizes="(max-width: 1155px) 100vw, 1155px" /></a></p>
<p>Распределённые базы данных выбирают две из трёх характеристик:</p>
<ul>
<li><strong>CP (Consistency + Partition Tolerance)</strong>
<ul>
<li>Строгая согласованность важнее доступности (во время сетевых проблем система может отказать в обслуживании)</li>
<li>Если важны точные, актуальные данные (банковские транзакции, финансовые операции).</li>
<li>Примеры СУБД: MongoDB (с Strong Consistency), HBase, Zookeeper</li>
</ul>
</li>
<li><strong>AP (Availability + Partition Tolerance)</strong>
<ul>
<li>Доступность важнее строгой согласованности (временно возможны устаревшие данные)</li>
<li>Если важнее всегда получать ответ, даже если данные могут быть устаревшими (соцсети, системы логирования)</li>
<li>Cassandra, DynamoDB, Riak</li>
</ul>
</li>
<li><strong>CA (Consistency + Availability)</strong>
<ul>
<li>Теоретически невозможна в распределённых системах, потому что сеть всегда может дать сбой</li>
<li>В реальном мире сеть не идеальна, поэтому отказоустойчивость (P) нельзя игнорировать.<br />Если сеть рвётся, приходится жертвовать либо C, либо A.</li>
<li>Реляционные базы в локальной сети (PostgreSQL, MySQL, MSSQL в монолитной архитектуре)</li>
</ul>
</li>
</ul>
<h2>Теорема CAP в отношении ACID и BASE</h2>
<ul>
<li><strong>ACID (Atomicity, Consistency, Isolation, Durability)</strong> – это не противоречие CAP, а подход для локальных транзакций.</li>
<li><strong>BASE (Basically Available, Soft State, Eventually Consistent)</strong> – модель NoSQL, строится вокруг AP-решений из CAP.</li>
</ul>
<blockquote>
<p>В реальности все системы балансируют между CAP, BASE и ACID, используя кванты согласованности и кэширование.</p>
</blockquote>
<hr />
<h2>В чем разница между базами данных ACID и BASE?</h2>
<blockquote>
<p>Аббревиатуры BASE и ACID специально подбирались так, чтобы в английском языке они противопоставлялись друг другу, поскольку эти же слова обозначают химически противоположные термины «щелочь» и «кислота».</p>
</blockquote>
<hr />
<p><strong>ACID и BASE</strong> – это модели транзакций для баз данных, которые определяют структуру данных и порядок работы с ними в базе данных. В контексте баз данных транзакцией называют любую операцию, которую база данных обрабатывает как единую единицу работы. Чтобы база данных оставалась согласованной, транзакция должна быть полностью завершена. Например, если вы переводите деньги с одного банковского счета на другой, нужно отразить эти изменения и на вашем счете, и на счете получателя. Такую транзакцию невозможно считать завершенной без выполнения обоих шагов.</p>
<p>В базах данных ACID приоритет отдается согласованности в ущерб доступности. Если на любом этапе транзакции возникает ошибка, вся транзакция полностью отменяется. Напротив, базы данных BASE отдают приоритет доступности в ущерб согласованности. При неудачном завершении транзакции пользователи могут временно получать несогласованные данные. Согласованность данных восстанавливается с некоторой задержкой.</p>
<h2>Для чего важны ACID и BASE?</h2>
<p>Например, когда покупатель добавляет товар в корзину на веб-сайте электронной коммерции, все остальные покупатели должны увидеть снижение уровня запасов этого товара. Если очередной покупатель добавит в корзину последний экземпляр, все остальные пользователи должны увидеть, что товара нет в наличии. Разработчикам баз данных нужно сделать выбор о поведении базы данных в том случае, если какая-либо операция в транзакции не может быть выполнена. База данных может действовать по одному из следующих принципов.</p>
<p>Отменить транзакцию и возвратить сообщение об ошибке, что снизит доступность, но гарантирует согласованность. Покупатель в таком случае не сможет добавить товар в корзину или другие покупатели не получат данных по некоторым товарам, пока не завершатся все операции добавления в корзину.</p>
<p>Продолжать остальные операции, что обеспечит максимально возможную доступность, но может приводить к несогласованности. В этом случае покупатель успешно добавит товар в корзину, а другие покупатели получат сведения об уровне запасов, но эти сведения будут неверными по крайней мере в течение некоторого времени.</p>
<p>В некоторых случаях согласованность имеет решающее значение, и тогда предпочтение отдается архитектуре ACID. Но есть и другие сценарии использования, в которых согласованность не критична. Например, когда вы принимаете запрос на добавление в друзья в социальной сети, никого не беспокоит, что другие пользователи некоторое время видят неточное количество друзей в вашем профиле. Вам более важно, чтобы доступ к ленте сообщений не пропадал на период синхронизации данных. В таких сценариях предпочтительным будет модель BASE.</p>
<h2>Может ли база данных быть одновременно ACID и BASE?</h2>
<p>Согласно теореме CAP, база данных может удовлетворять только двум из трех требований: согласованность, доступность и устойчивость к разделению. Обе модели баз данных ACID и BASE обеспечивают устойчивость к разделению, то есть не могут быть одновременно высокосогласованными и постоянно доступными. Это означает, что любая база данных может больше или меньше соответствовать концепции ACID или BASE, но не может использовать оба подхода одновременно. Например, базы данных SQL структурированы по модели ACID, а базы данных NoSQL используют архитектуру BASE. Некоторые базы данных NoSQL могут обладать определенными свойствами, характерными для ACID, но никогда не могут полностью соответствовать концепции ACID.</p>
<h2>Когда что использовать: ACID в сравнении с BASE</h2>
<p>Несмотря на существенные различия, системы баз данных ACID и BASE применяются в разных приложениях. ACID идеально подходит для корпоративных приложений, в которых требуются согласованность, надежность и предсказуемость данных. Например, банки всегда используют для хранения транзакций клиентов базу данных с архитектурой ACID, поскольку целостность данных здесь является главным приоритетом. В свою очередь, базы данных BASE лучше подходят для аналитической обработки слабо структурированных данных в больших объемах. Например, веб-сайты электронной коммерции используют базы данных с архитектурой BASE для хранения цен на товары, которые часто меняются. В этом случае точность отображения цен менее важна, чем своевременное информирование клиентов об изменении цены.</p>
<h2>Ключевые различия между ACID и BASE</h2>
<p><span style="color: #ff6600;"><strong>При выборе между моделями транзакций ACID и BASE для баз данных нужно искать компромиссы.</strong></span></p>
<p><strong>Масштабирование</strong></p>
<p>База данных с моделью транзакций ACID масштабируется хуже, поскольку она ориентирована на согласованность. Для любой записи в любой момент времени может выполняться только одна транзакция, что затрудняет горизонтальное масштабирование.</p>
<p>С другой стороны, базу данных с архитектурой BASE легко масштабировать по горизонтали, поскольку нет необходимости поддерживать строгую согласованность. Простое добавление нескольких узлов в кластер позволяет базе данных с архитектурой BASE повысить доступность данных, которая является основополагающим принципом этой архитектуры базы данных.</p>
<p><strong>Гибкость</strong></p>
<p>Базы данных ACID менее гибки в обработке данных. Такая база данных должна гарантировать немедленную согласованность, поэтому она может ограничивать доступ к некоторым приложениям в случае сбоев в сети или в электроснабжении. Аналогичным образом, приложениям приходится ждать своей очереди на обновление данных, если другие программные модули уже обрабатывают некоторую запись. Базы данных BASE намного более гибкие. В архитектуре BASE не используются строгие ограничения, и приложения могут изменять записи по мере появления обновлений.</p>
<p><strong>Производительность</strong></p>
<p>База данных ACID может испытывать проблемы с производительностью при обработке больших объемов данных или параллельных запросов. Поскольку все операции обрабатываются в строгом порядке, накладные расходы на поддержание целостности транзакций приводят к дополнительным задержкам, которые влияют на доступ всех приложений к затронутой записи.</p>
<p>Напротив, к базе данных BASE приложения могут обращаться для обработки записей в любое время. Это позволяет избежать длительного времени ожидания и повышает пропускную способность базы данных.</p>
<p><strong>Синхронизация</strong></p>
<p>База данных с архитектурой ACID нуждается в механизме синхронизации, чтобы выполненные в транзакции изменения были зафиксированы одновременно во всех связанных записях. В то же время, каждая изменяемая запись должны быть заблокирована от доступа других сторон до завершения или отмены транзакции. База данных BASE, в свою очередь, работает без блокировки записей и поддерживает только согласованность «в конечном счете», без каких-либо гарантий по времени ее достижения. При работе с базами данных BASE разработчики понимают, что при обработке записей могут и будут возникать несоответствия, и принимают необходимые меры предосторожности в самом приложении.</p>
<h1>Колоночные базы данных</h1>
<p><strong>ClickHouse, Vertica, Teradata</strong> – это колонночные базы данных, предназначенные для аналитики и обработки больших данных (Big Data). Они не совсем NoSQL, но и не классические реляционные базы, потому что работают по другой модели, ориентированной на быструю агрегацию и аналитические запросы.</p>
<p><strong>Как они работают?</strong></p>
<ul>
<li><strong>Колонночное хранение</strong> – данные хранятся не построчно (как в классических реляционных БД), а по колонкам. Это ускоряет агрегатные операции (SUM, AVG, COUNT).</li>
<li><strong>Массовая параллельная обработка (MPP &#8212; Massively Parallel Processing)</strong> – база распределяет нагрузку между узлами кластера, что ускоряет вычисления.</li>
<li><strong>Жесткая схема</strong> – в отличие от NoSQL, эти базы обычно требуют заранее заданной структуры данных.</li>
</ul>
<p><strong>ACID или BASE?</strong></p>
<p>Эти системы не используют ни чистый ACID, ни BASE, а скорее компромиссный подход:</p>


<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>База данных</th><th>Модель согласованности</th><th>Доступность</th><th>Транзакции</th></tr></thead><tbody><tr><td><strong>ClickHouse</strong></td><td>Eventual Consistency (не гарантирует строгую ACID-согласованность, данные могут быть &#171;размазанными&#187; в кластере)</td><td>Высокая (оптимизирована для чтения)</td><td>Поддерживает &#171;атомарные&#187; вставки, но нет полноценной поддержки ACID</td></tr><tr><td><strong>Vertica</strong></td><td>Strong Consistency (более строгая согласованность, чем ClickHouse)</td><td>Высокая, но зависит от кластера</td><td>Ограниченная поддержка транзакций</td></tr><tr><td><strong>Teradata</strong></td><td>Strong Consistency (ACID-like)</td><td>Высокая, но заточена под масштабируемость</td><td>Поддерживает транзакции, но основное назначение – аналитика</td></tr></tbody></table></figure>


<p>Они ближе к Eventual Consistency (Окончательная согласованность), но не совсем BASE и не ACID. Они оптимизированы под скорость аналитики, жертвуя полной транзакционной поддержкой (как в ACID) ради высокой производительности.</p>
<h1>А как работает GreenPlum?</h1>
<p><strong>Greenplum</strong> – это масштабируемая MPP (Massively Parallel Processing) реляционная СУБД, основанная на PostgreSQL. Она предназначена для аналитических задач и хранилищ данных (DWH – Data Warehouse).</p>
<ul>
<li><strong>Тип:</strong> Колонно-строчная реляционная СУБД (по структуре ближе к классическим РСУБД, но заточена под аналитику).</li>
<li><strong>Используемая модель:</strong> ACID для отдельных сегментов, но в целом ориентирована на MPP-анализ (компромисс между ACID и Eventual Consistency).</li>
<li><strong>Область применения:</strong> Big Data, хранилища данных, аналитические запросы (OLAP).</li>
</ul>
<blockquote>
<p>Greenplum – это гибрид между классической ACID-реляционной СУБД (PostgreSQL) и MPP-анализом больших данных.</p>
<hr /></blockquote>
<p><strong style="font-family: Roboto; font-size: revert;">Как работает Greenplum?</strong></p>
<ul>
<li><strong>Massively Parallel Processing (MPP)</strong> – база данных делится на узлы (Data Nodes), каждый из которых выполняет свою часть запроса параллельно.</li>
<li><strong>Segment-based Architecture</strong> – данные хранятся в разделах (сегментах), а главный узел (Master) управляет запросами.</li>
<li><strong>ACID внутри сегментов</strong> – каждая нода гарантирует ACID на своем уровне, но согласованность между узлами достигается за счёт распределенных транзакций.</li>
<li><strong>Ориентация на аналитические запросы (OLAP)</strong> – поддержка SQL, индексов, распределённой агрегации.</li>
</ul>
<blockquote>
<p>По модели – не совсем ACID и не BASE, а гибрид ACID + MPP, где каждый сегмент ACID, но согласованность распределённых транзакций не моментальная.</p>
</blockquote>
<h1>Компромиссы в системном дизайне: 2PC, 3PC, Saga, BASE</h1>
<p><strong>Компромисс в инженерии</strong> — это осознанный выбор одного свойства системы в ущерб другому. Это не «ошибка» и не «плохое решение», а неизбежная плата за достижение определённой цели.</p>
<p>Компромиссы возникают, потому что ресурсы ограничены (время, сеть, память, обработка), а свойства системы часто противоречат друг другу.</p>
<p><strong>Примеры противоречий:</strong></p>
<ul>
<li>Быстродействие <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2194.png" alt="↔" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Надёжность</li>
<li>Согласованность <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2194.png" alt="↔" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Доступность (CAP-теорема)</li>
<li>Масштабируемость <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2194.png" alt="↔" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Простота архитектуры</li>
<li>Атомарность <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2194.png" alt="↔" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Распределённость</li>
</ul>
<h2>Сводка по компромиссам</h2>
<table>
<thead>
<tr>
<th>Подход</th>
<th>Консистентность</th>
<th>Доступность</th>
<th>Отказоустойчивость</th>
<th>Производительность</th>
<th>Сложность</th>
<th>Атомарность</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>2PC</strong></td>
<td>Высокая</td>
<td>Низкая</td>
<td>Низкая</td>
<td>Низкая</td>
<td>Средняя</td>
<td>Да</td>
</tr>
<tr>
<td><strong>3PC</strong></td>
<td>Высокая</td>
<td>Ниже средней</td>
<td>Средняя</td>
<td>Ниже средней</td>
<td>Высокая</td>
<td>Да</td>
</tr>
<tr>
<td><strong>Saga</strong></td>
<td>Средняя</td>
<td>Высокая</td>
<td>Высокая</td>
<td>Средняя/высокая</td>
<td>Средняя</td>
<td>Нет (компенсации)</td>
</tr>
<tr>
<td><strong>BASE</strong></td>
<td>Низкая (eventual)</td>
<td>Высокая</td>
<td>Высокая</td>
<td>Высокая</td>
<td>Низкая</td>
<td>Нет</td>
</tr>
</tbody>
</table>
<ul>
<li>Если важна целостность и критичность (банки, финансы): ACID + 2PC (или 3PC).</li>
<li>Если нужны микросервисы и высокая доступность: Saga.</li>
<li>Если важна масштабируемость и отказоустойчивость (соцсети, IoT): BASE.</li>
</ul>
<p><strong>Компенсация</strong> — это обратная операция, предназначенная для отмены или нейтрализации эффекта уже выполненной операции.</p>
<blockquote>
<p>Если ты выполнил шаг, но позже вся последовательность должна быть отменена, ты не можешь просто «откатить» как в SQL — ты должен выполнить противоположное действие, которое компенсирует последствия.</p>
</blockquote>
<h2>Еще раз вернемся к САР теореме</h2>
<p>Это фундаментальная концепция распределённых систем, утверждающая, что в условиях сетовых сбоев система может гарантировать только два из трёх свойств:</p>
<ul>
<li><strong>Consistency (согласованность):</strong> все узлы видят одинаковые данные одновременно.</li>
<li><strong>Availability (доступность):</strong> каждый запрос получает ответ (успешный или нет).</li>
<li><strong>Partition tolerance (устойчивость к разделению):</strong> система продолжает работу при потере связи между частями сети.</li>
</ul>
<h2>Протокол согласования 2PC (Two-Phase Commit)</h2>
<p><strong>Компромисс:</strong><br /><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2714.png" alt="✔" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Консистентность ↑<br />✘ Производительность ↓<br />✘ Отказоустойчивость ↓</p>
<p><strong>Описание:</strong><br />Протокол с двумя фазами:</p>
<ul>
<li><strong>Prepare</strong> — координатор опрашивает участников, готовы ли они зафиксировать транзакцию.</li>
<li><strong>Commit</strong> — если все &#171;за&#187;, координатор отправляет &#171;commit&#187;, иначе &#171;abort&#187;.</li>
</ul>
<p><strong>Недостатки:</strong></p>
<ul>
<li>Координатор — Single Point of Failure.</li>
<li>Участники могут зависнуть в неопределённом состоянии при сбое координатора между фазами.</li>
<li>Блокирующий протокол — участники не могут принять решение самостоятельно, ждут координатора.</li>
</ul>
<h2>Протокол согласования 3PC (Three-Phase Commit)</h2>
<p><strong>Компромисс:</strong><br /><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2714.png" alt="✔" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Отказоустойчивость ↑<br />✘ Сложность ↑<br /><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2714.png" alt="✔" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Более «неблокирующий», чем 2PC</p>
<p><strong>Описание:</strong><br />Добавляется промежуточная фаза между prepare и commit:</p>
<ul>
<li><strong>Can Commit</strong> — координатор спрашивает, могут ли участники зафиксировать.</li>
<li><strong>Pre-Commit</strong> — если все согласны, координатор даёт «готовьтесь к коммиту».</li>
<li><strong>Do Commit</strong> — координатор сообщает финальное решение.</li>
</ul>
<p><strong>Преимущества:</strong></p>
<ul>
<li>Уменьшение вероятности блокировки за счёт промежуточной фазы.</li>
<li>Участники могут принять решение сами, если координатор пропал после 2-й фазы.</li>
</ul>
<p><strong>Недостатки:</strong></p>
<ul>
<li>Более сложная реализация.</li>
<li>Больше сетевых взаимодействий → выше задержки.</li>
</ul>
<h2>Протокол согласования Saga Pattern (длинные/компенсируемые транзакции)</h2>
<p>В классических ACID-транзакциях ты можешь сделать <code>ROLLBACK</code>, и всё вернётся в исходное состояние. Но в распределённых системах (микросервисы, веб-сервисы) нет общей транзакции. Поэтому вместо отмены используется Saga, где каждая операция:</p>
<ul>
<li>Или завершается успешно,</li>
<li>Или компенсируется вручную.</li>
</ul>
<p><strong>Компромисс:</strong><br /><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2714.png" alt="✔" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Доступность ↑<br />✘ Атомарность ↓</p>
<p><strong>Описание:</strong><br />Сага разбивает большую транзакцию на серию локальных (атомарных в пределах сервиса) операций с компенсациями. Если одна операция неудачна, запускается обратная последовательность для отката предыдущих шагов.</p>
<p><strong>Пример:</strong></p>
<ul>
<li>Зарезервировать номер в отеле.</li>
<li>Купить билет.</li>
<li>Забронировать такси.<br />Если шаг 2 не удался — отменить шаг 1 (компенсация).</li>
</ul>
<table>
<thead>
<tr>
<th>Шаг</th>
<th>Операция</th>
<th>Компенсация</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>Зарезервировать номер</td>
<td>Отменить бронь</td>
</tr>
<tr>
<td>2</td>
<td>Списать деньги</td>
<td>Вернуть деньги</td>
</tr>
<tr>
<td>3</td>
<td>Забронировать трансфер</td>
<td>Отменить трансфер</td>
</tr>
</tbody>
</table>
<p><strong>Типы:</strong></p>
<ul>
<li>Orchestration (централизованный управляющий)</li>
<li>Choreography (каждый сервис реагирует на события)</li>
</ul>
<p><strong>Недостатки:</strong></p>
<ul>
<li>Нет строгой атомарности.</li>
<li>Не всегда возможна полная компенсация.</li>
<li>Сложность логики откатов.</li>
</ul>
<h2>BASE-модель (противопоставляется ACID)</h2>
<p>Компромисс:</p>
<p><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2714.png" alt="✔" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Масштабируемость ↑<br />✘ Нет строгой консистентности (eventual consistency)</p>
<p><strong>Расшифровка:</strong></p>
<ul>
<li><strong>Basically Available</strong> — система отвечает даже при сбоях.</li>
<li><strong>Soft state</strong> — состояние может меняться со временем (в т.ч. без ввода данных).</li>
<li><strong>Eventual consistency</strong> — данные станут согласованными в будущем.</li>
</ul>
<p><strong>Применяется в:</strong></p>
<ul>
<li>NoSQL-базы (Cassandra, DynamoDB)</li>
<li>Высоконагруженные распределённые системы</li>
</ul>
<p><strong>Плюсы:</strong></p>
<ul>
<li>Высокая масштабируемость.</li>
<li>Подходит для отказоустойчивых систем с миллионами пользователей.</li>
</ul>
<p><strong>Минусы:</strong></p>
<ul>
<li>Отсутствие строгой согласованности — требует проектировать бизнес-логику с этим учетом.</li>
</ul>
<h2>Видео Филипп Вагнер «Распределенные транзакции в условиях микросервисной архитектуры»</h2>
<p><iframe title="Филипп Вагнер «Распределенные транзакции в условиях микросервисной архитектуры»" width="1170" height="658" src="https://www.youtube.com/embed/P98oMiVCnq8?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe></p>
<h2>Видео Паттерн «Saga» в бронировании отелей · Антон Цитульский</h2>
<p><iframe title="Паттерн «Saga» в бронировании отелей · Антон Цитульский" width="1170" height="658" src="https://www.youtube.com/embed/owCEP2rKV9I?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe></p>
<h1>Использованные ссылки для написания статьи</h1>
<ul>
<li><a href="https://blog.algomaster.io/p/what-are-acid-transactions-in-databases" target="_blank" rel="noopener">What are ACID Transactions in Databases?</a></li>
<li><a href="https://aws.amazon.com/ru/compare/the-difference-between-acid-and-base-database/" target="_blank" rel="noopener">В чем разница между базами данных ACID и BASE?</a></li>
</ul><p>Сообщение <a href="https://datatalks.ru/acid-base-cap-theorem-for-databases/">Требования ACID. BASE модель. CAP теорема</a> появились сначала на <a href="https://datatalks.ru">DataTalks.RU. Data Engineering / DWH / Data Pipeline</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://datatalks.ru/acid-base-cap-theorem-for-databases/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Инкрементальное обновление данных &#8212; Incremental Data Refresh</title>
		<link>https://datatalks.ru/incremental-data-refresh-sql-patterns/</link>
					<comments>https://datatalks.ru/incremental-data-refresh-sql-patterns/#respond</comments>
		
		<dc:creator><![CDATA[Data Engineer (Admin)]]></dc:creator>
		<pubDate>Tue, 07 Jan 2025 19:51:27 +0000</pubDate>
				<category><![CDATA[DWH]]></category>
		<category><![CDATA[Append]]></category>
		<category><![CDATA[Append Only (Anti Join)]]></category>
		<category><![CDATA[CDC]]></category>
		<category><![CDATA[Change Data Capture]]></category>
		<category><![CDATA[Delete + Insert]]></category>
		<category><![CDATA[full refresh]]></category>
		<category><![CDATA[incremental strategy]]></category>
		<category><![CDATA[Insert Overwrite]]></category>
		<category><![CDATA[Log-based CDC]]></category>
		<category><![CDATA[Merge]]></category>
		<category><![CDATA[Query-based CDC]]></category>
		<category><![CDATA[SCD]]></category>
		<category><![CDATA[Slowly Changing Dimensions]]></category>
		<category><![CDATA[Swap partitions]]></category>
		<category><![CDATA[Trigger-based CDC]]></category>
		<category><![CDATA[Upsert]]></category>
		<guid isPermaLink="false">https://datatalks.ru/?p=627</guid>

					<description><![CDATA[<p>Шаблоны обновлений данных в DWH Эта статья частично пересекается со статьей Понимание инкрементальных стратегий dbt, часть 1 (рекомендую ознакомиться). Изменение данных — одна из основных задач для команд инженерии данных, особенно при переходе от одной технологии к другой. Обсудим команды DML в языке SQL. Ниже будут рассмотрены основные схемы обновления данных в Data Engineering. Стратегия [&#8230;]</p>
<p>Сообщение <a href="https://datatalks.ru/incremental-data-refresh-sql-patterns/">Инкрементальное обновление данных &#8212; Incremental Data Refresh</a> появились сначала на <a href="https://datatalks.ru">DataTalks.RU. Data Engineering / DWH / Data Pipeline</a>.</p>
]]></description>
										<content:encoded><![CDATA[<h1>Шаблоны обновлений данных в DWH</h1>
<p>Эта статья частично пересекается со статьей <strong><a href="https://datatalks.ru/understanding-dbt-incremental-strategies-part-1/" target="_blank" rel="noopener">Понимание инкрементальных стратегий dbt, часть 1</a></strong> <span style="color: #ff6600;">(рекомендую ознакомиться)</span>.</p>
<hr />
<p>Изменение данных — одна из основных задач для команд инженерии данных, особенно при переходе от одной технологии к другой. Обсудим команды DML в языке SQL.</p>
<p>Ниже будут рассмотрены основные схемы обновления данных в Data Engineering.</p>
<h2>Стратегия полного обновления (full refresh)</h2>
<h3><strong>Вариант 1 &#8212; Truncate Table</strong></h3>
<p>Стирание — это шаблон обновления, который ничего не обновляет. Он просто удаляет старые данные. При обновлении по схеме «стирание и перезагрузка» (truncate-and-reload) таблица очищается от данных, а преобразования запускаются заново и загружаются в таблицу, фактически создавая её новую версию.</p>
<p><strong>Пример:</strong></p><pre class="urvanov-syntax-highlighter-plain-tag">TRUNCATE TABLE target_table;  

INSERT INTO target_table  
SELECT customer_id, SUM(amount) AS total_amount  
FROM source_table  
WHERE order_date &gt;= '2024-12-01' AND order_date &lt;= '2024-12-31'  
GROUP BY customer_id;</pre><p></p>
<h3><strong>Вариант 2 &#8212; Drop Table</strong></h3>
<p>Replace (Drop and Recreate) &#8212; Удаление таблицы и создание новой с новыми данными.</p>
<p><strong>Применение:</strong></p>
<p>Используется для временных или промежуточных таблиц, которые проще пересоздать, чем обновить.</p>
<p><strong>Пример:</strong></p><pre class="urvanov-syntax-highlighter-plain-tag">DROP TABLE IF EXISTS target_table;  

CREATE TABLE target_table AS  
SELECT *  
FROM source_table;</pre><p></p>
<h3><strong>Вариант 3 &#8212; Собираем временную таблицу и делаем переименование</strong></h3>
<p>Удаление таблицы или ее очистка может приводить к &#171;морганию данных&#187; (когда на период пересчета и загрузки данных таблица остается пустой), поэтому имеет смысл при небольших объемах данных готовить сбоку целевую заново рассчитанную таблицу и затем ее менять с целевой местами.</p>
<p><a href="https://datatalks.ru/wp-content/uploads/2025/01/tables_change_rename_swap.jpeg"><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-809" src="https://datatalks.ru/wp-content/uploads/2025/01/tables_change_rename_swap.jpeg" alt="" width="252" height="238" /></a></p>
<p>В разных базах данных по разному можно выполнить переименование таблиц, в ClickHouse есть например <a href="https://clickhouse.com/docs/ru/sql-reference/statements/exchange" target="_blank" rel="noopener">EXCHANGE</a>.</p>
<h2>Append Only (Anti Join)</h2>
<blockquote><p><span style="color: #ff6600;">Append (Anti Join)</span> &#8212; Добавление только новых записей, которых нет в целевой таблице.</p>
<p><a href="https://datatalks.ru/wp-content/uploads/2025/01/append.png"><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-657" src="https://datatalks.ru/wp-content/uploads/2025/01/append.png" alt="" width="1413" height="753" srcset="https://datatalks.ru/wp-content/uploads/2025/01/append.png 1413w, https://datatalks.ru/wp-content/uploads/2025/01/append-300x160.png 300w, https://datatalks.ru/wp-content/uploads/2025/01/append-1024x546.png 1024w, https://datatalks.ru/wp-content/uploads/2025/01/append-768x409.png 768w, https://datatalks.ru/wp-content/uploads/2025/01/append-450x240.png 450w, https://datatalks.ru/wp-content/uploads/2025/01/append-780x416.png 780w" sizes="(max-width: 1413px) 100vw, 1413px" /></a></p></blockquote>
<p><strong>Шаблон «только вставка»</strong> позволяет добавлять новые записи без изменения или удаления старых. Такие шаблоны могут использоваться для поддержания текущего состояния данных. Например, вставляются новые версии записей без удаления старых, а запрос или представление показывает текущее состояние данных, находя самую новую запись по первичному ключу.</p>
<p>В базах данных на основе столбцов первичные ключи обычно не применяются. Это концепция, используемая инженерами для управления текущим состоянием таблицы. Однако поиск последней записи во время запроса может быть вычислительно затратным.</p>
<p>Альтернативой может быть использование материализованного представления, в котором хранятся только актуальные записи, или использование таблицы для вставки всех записей и другой таблицы для хранения текущего состояния.</p>
<p>При вставке данных в OLAP-базы на основе столбцов часто возникает проблема, когда инженеры, переходящие со строковых систем, используют однострочную вставку. Этот антипаттерн создаёт огромную нагрузку на систему. Данные записываются в множество отдельных файлов, что снижает эффективность их последующего считывания. Рекомендуется загружать данные микропакетами или пакетами.</p>
<p>Исключением из правила «не выполнять частую вставку» является усовершенствованная лямбда-архитектура, применяемая в BigQuery и Apache Druid. Она сочетает потоковый буфер с хранилищем на основе столбцов.</p>
<p><strong>Применение Append:</strong></p>
<p>Используется, когда обновление данных подразумевает исключительно добавление новых строк (например, лог-файлы или потоковые данные).</p>
<p><strong>Принцип работы:</strong></p>
<ol>
<li>Выполняется проверка на наличие данных в целевой таблице с использованием ANTI JOIN.</li>
<li>Данные, которых нет в целевой таблице, добавляются.</li>
</ol>
<p><strong>Пример:</strong></p>
<p>Добавление новых заказов, которых еще нет в основной таблице.</p><pre class="urvanov-syntax-highlighter-plain-tag">INSERT INTO target_table (id, order_date, amount)  
SELECT s.id, s.order_date, s.amount  
FROM source_table s  
LEFT JOIN target_table t ON s.id = t.id  
WHERE t.id IS NULL; -- Только те записи, которых нет в целевой таблице</pre><p></p>
<h2>Merge (также называется Upsert)</h2>
<blockquote><p><span style="color: #ff6600;">Upsert / Merge</span> &#8212; Обновление существующих данных или добавление новых.</p>
<p><a href="https://datatalks.ru/wp-content/uploads/2025/01/Merge.png"><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-658" src="https://datatalks.ru/wp-content/uploads/2025/01/Merge.png" alt="" width="1413" height="753" srcset="https://datatalks.ru/wp-content/uploads/2025/01/Merge.png 1413w, https://datatalks.ru/wp-content/uploads/2025/01/Merge-300x160.png 300w, https://datatalks.ru/wp-content/uploads/2025/01/Merge-1024x546.png 1024w, https://datatalks.ru/wp-content/uploads/2025/01/Merge-768x409.png 768w, https://datatalks.ru/wp-content/uploads/2025/01/Merge-450x240.png 450w, https://datatalks.ru/wp-content/uploads/2025/01/Merge-780x416.png 780w" sizes="(max-width: 1413px) 100vw, 1413px" /></a></p></blockquote>
<p><strong>Merge (он же Upsert)</strong> — это операция базы данных, которая позволяет сделать выбор между вставкой новой строки или обновлением существующих строк в зависимости от того, выполняется ли условие (например, ограничение уникальности). Эта операция особенно полезна, когда вы не уверены, существуют ли уже данные в базе данных.</p>
<hr />
<p>Операция Upsert (обновление + вставка) вызывает проблемы у инженеров, особенно при переходе от строковых баз данных к облачным хранилищам на основе столбцов.</p>
<p>При Upsert исходные записи ищут совпадения с целевой таблицей по первичному ключу или другому условию. Если совпадение найдено, запись обновляется. Если нет — добавляется новая. Слияние дополняет Upsert возможностью удаления записей.</p>
<p>Файловые системы не поддерживают обновление файлов на месте. Они используют технологию копирования при записи (Copy-on-write, COW): при изменении или удалении записи переписывается весь файл. Это делает операции обновления сложными.</p>
<p>Некоторые базы данных на основе столбцов, такие как Vertica, скрывают сложность COW, обновляя записи и указатели файлов. Облачные хранилища данных поддерживают обновления и слияния, хотя их выполнение может быть ресурсоёмким.</p>
<p>Обновления редко приводят к переписыванию всей таблицы. Эффективность зависит от стратегии разбиения и кластеризации.</p>
<p>Частота обновлений также имеет значение. Вместо попыток выполнять слияния в режиме реального времени разумнее делать их раз в час.</p>
<p>BigQuery поддерживает потоковую вставку записей с дедупликацией данных в реальном времени. Druid использует двухуровневое хранилище для сверхбыстрых запросов.</p>
<p><strong>Применение:</strong></p>
<p>Используется для синхронизации данных, когда необходимо как обновить существующие строки, так и добавить новые.</p>
<p><strong>Принцип работы:</strong></p>
<ol>
<li>Выполняется проверка на совпадение ключей между источником и целевой таблицей.</li>
<li>При совпадении ключа выполняется обновление.</li>
<li>При отсутствии совпадения выполняется вставка.</li>
</ol>
<p><strong>Пример:</strong></p>
<p>Синхронизация информации о пользователях.</p><pre class="urvanov-syntax-highlighter-plain-tag">MERGE INTO target_table AS t  
USING source_table AS s  
ON t.id = s.id  
WHEN MATCHED THEN  
    UPDATE SET t.name = s.name, t.email = s.email  
WHEN NOT MATCHED THEN  
    INSERT (id, name, email)  
    VALUES (s.id, s.name, s.email);</pre><p></p>
<h2>Delete + Insert</h2>
<p>Удаление данных важно, если исходная система требует их удаления в соответствии с нормативными требованиями. В системах на основе столбцов удаление обходится дороже, чем вставка.</p>
<p>Существуют два вида удаления: жёсткое и мягкое. Жёсткое удаление окончательно удаляет запись из базы данных, а мягкое помечает запись как «удалённую». Мягкое удаление полезно, если запись не нужно удалять навсегда, но нужно исключить из результатов запроса.</p>
<p>Третий подход — вставка удаления. Он добавляет новую запись с флагом deleted, не изменяя предыдущую версию. Это позволяет использовать шаблон «только вставка», учитывая удаление. Однако такой подход усложняет запросы для получения актуального состояния данных.</p>
<blockquote><p><span style="color: #ff6600;">Delta Updates (Change-Based Updates)</span> &#8212; Применение изменений к целевой таблице на основе метки времени или инкрементального идентификатора.</p>
<p><a href="https://datatalks.ru/wp-content/uploads/2024/12/dbt_incremental_delete_plus_insert.jpeg" target="_blank" rel="noopener"><img loading="lazy" decoding="async" class="aligncenter wp-image-422 size-full" src="https://datatalks.ru/wp-content/uploads/2024/12/dbt_incremental_delete_plus_insert.jpeg" alt="" width="1662" height="773" srcset="https://datatalks.ru/wp-content/uploads/2024/12/dbt_incremental_delete_plus_insert.jpeg 1662w, https://datatalks.ru/wp-content/uploads/2024/12/dbt_incremental_delete_plus_insert-300x140.jpeg 300w, https://datatalks.ru/wp-content/uploads/2024/12/dbt_incremental_delete_plus_insert-1024x476.jpeg 1024w, https://datatalks.ru/wp-content/uploads/2024/12/dbt_incremental_delete_plus_insert-768x357.jpeg 768w, https://datatalks.ru/wp-content/uploads/2024/12/dbt_incremental_delete_plus_insert-1536x714.jpeg 1536w, https://datatalks.ru/wp-content/uploads/2024/12/dbt_incremental_delete_plus_insert-450x209.jpeg 450w, https://datatalks.ru/wp-content/uploads/2024/12/dbt_incremental_delete_plus_insert-780x363.jpeg 780w, https://datatalks.ru/wp-content/uploads/2024/12/dbt_incremental_delete_plus_insert-1600x744.jpeg 1600w" sizes="(max-width: 1662px) 100vw, 1662px" /></a></p></blockquote>
<p><strong>Применение:</strong></p>
<p>Используется, если источник предоставляет только измененные записи.</p>
<p><strong>Пример:</strong></p>
<p>Обновление заказов, измененных после последней загрузки.</p><pre class="urvanov-syntax-highlighter-plain-tag">-- Удаление старых данных
DELETE FROM target_table  
WHERE id IN (SELECT id FROM source_table WHERE updated_at &gt; @last_load_time);  

-- Вставка новых данных
INSERT INTO target_table  
SELECT *  
FROM source_table  
WHERE updated_at &gt; @last_load_time;</pre><p></p>
<h2>Insert Overwrite / Swap partitions</h2>
<blockquote><p><span style="color: #ff6600;">Windowed Updates (Partition-Based)</span> &#8212; это Обновление данных по партициям (например, по диапазонам дат).</p>
<p><a href="https://datatalks.ru/wp-content/uploads/2025/01/Partition.png"><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-660" src="https://datatalks.ru/wp-content/uploads/2025/01/Partition.png" alt="" width="1413" height="753" srcset="https://datatalks.ru/wp-content/uploads/2025/01/Partition.png 1413w, https://datatalks.ru/wp-content/uploads/2025/01/Partition-300x160.png 300w, https://datatalks.ru/wp-content/uploads/2025/01/Partition-1024x546.png 1024w, https://datatalks.ru/wp-content/uploads/2025/01/Partition-768x409.png 768w, https://datatalks.ru/wp-content/uploads/2025/01/Partition-450x240.png 450w, https://datatalks.ru/wp-content/uploads/2025/01/Partition-780x416.png 780w" sizes="(max-width: 1413px) 100vw, 1413px" /></a></p></blockquote>
<p><strong>Схема работы с партициями следующая:</strong></p>
<ol>
<li>Собирается таблица с обновленными партициями.</li>
<li>Далее меняются партиции целевой таблицы (target table) и временной.</li>
<li>После замены существующих партиций и вставки новых партиций &#8212; временная таблица удаляется</li>
</ol>
<p><strong>Пример для ClickHouse:</strong></p><pre class="urvanov-syntax-highlighter-plain-tag">ALTER TABLE test.hits_local REPLACE PARTITION '2020-10-27' FROM test.hits_local_tmp;
ALTER TABLE test.hits_local_tmp DROP PARTITION '2020-10-27';</pre><p></p>
<h3><strong>Работа с партициями в ClickHouse</strong></h3>
<p>Для работы с <a href="https://clickhouse.com/docs/ru/engines/table-engines/mergetree-family/custom-partitioning-key">партициями</a> доступны следующие операции:</p>
<ul>
<li><a href="https://clickhouse.com/docs/ru/sql-reference/statements/alter/partition#alter_detach-partition">DETACH PARTITION</a> — перенести партицию в директорию <code>detached</code>;</li>
<li><a href="https://clickhouse.com/docs/ru/sql-reference/statements/alter/partition#alter_drop-partition">DROP PARTITION</a> — удалить партицию;</li>
<li><a href="https://clickhouse.com/docs/ru/sql-reference/statements/alter/partition#alter_attach-partition">ATTACH PARTITION|PART</a> — добавить партицию/кусок в таблицу из директории <code>detached</code>;</li>
<li><a href="https://clickhouse.com/docs/ru/sql-reference/statements/alter/partition#alter_attach-partition-from">ATTACH PARTITION FROM</a> — скопировать партицию из другой таблицы;</li>
<li><a href="https://clickhouse.com/docs/ru/sql-reference/statements/alter/partition#alter_replace-partition">REPLACE PARTITION</a> — скопировать партицию из другой таблицы с заменой;</li>
<li><a href="https://clickhouse.com/docs/ru/sql-reference/statements/alter/partition#alter_move_to_table-partition">MOVE PARTITION TO TABLE</a> — переместить партицию в другую таблицу;</li>
<li><a href="https://clickhouse.com/docs/ru/sql-reference/statements/alter/partition#alter_clear-column-partition">CLEAR COLUMN IN PARTITION</a> — удалить все значения в столбце для заданной партиции;</li>
<li><a href="https://clickhouse.com/docs/ru/sql-reference/statements/alter/partition#alter_clear-index-partition">CLEAR INDEX IN PARTITION</a> — очистить построенные вторичные индексы для заданной партиции;</li>
<li><a href="https://clickhouse.com/docs/ru/sql-reference/statements/alter/partition#alter_freeze-partition">FREEZE PARTITION</a> — создать резервную копию партиции;</li>
<li><a href="https://clickhouse.com/docs/ru/sql-reference/statements/alter/partition#alter_unfreeze-partition">UNFREEZE PARTITION</a> — удалить резервную копию партиции;</li>
<li><a href="https://clickhouse.com/docs/ru/sql-reference/statements/alter/partition#alter_fetch-partition">FETCH PARTITION|PART</a> — скачать партицию/кусок с другого сервера;</li>
<li><a href="https://clickhouse.com/docs/ru/sql-reference/statements/alter/partition#alter_move-partition">MOVE PARTITION|PART</a> — переместить партицию/кускок на другой диск или том.</li>
<li><a href="https://clickhouse.com/docs/ru/sql-reference/statements/alter/partition#update-in-partition">UPDATE IN PARTITION</a> — обновить данные внутри партиции по условию.</li>
<li><a href="https://clickhouse.com/docs/ru/sql-reference/statements/alter/partition#delete-in-partition">DELETE IN PARTITION</a> — удалить данные внутри партиции по условию.</li>
</ul>
<h1>SCD (Slowly Changing Dimensions)</h1>
<p><strong>Медленно изменяющиеся измерения в хранилище данных (Slowly Changing Dimensions, SCD)</strong> — важная концепция, которая используется для включения исторического аспекта данных в аналитическую систему. Как вы знаете, хранилище данных используется для анализа исторических данных, важно хранить различные состояния данных.</p>
<p>В хранилище данных у нас есть таблицы фактов и измерений для хранения данных. Таблицы измерений используются для анализа мер в таблицах фактов. В среде данных данные инициируются в операционных базах данных, и данные будут извлечены-преобразованы-загружены (ETL) в хранилище данных для соответствия аналитической среде.</p>
<p>Customer, Product — примеры таблиц Dimensional. Эти атрибуты измерений изменяются с течением времени, и в хранилище данных нам необходимо поддерживать историю. В операционных системах мы можем перезаписывать измененные атрибуты, поскольку нам могут не понадобиться исторические аспекты данных. Поскольку нашей основной целью в хранилище данных является анализ данных с точки зрения истории, мы не сможем просто перезаписать данные, и нам необходимо реализовать специальные методы для поддержания истории с учетом аналитических и объемных аспектов хранилища данных. Эта реализация выполняется с использованием медленно изменяющихся измерений в хранилище данных.</p>
<h2><strong>Типы SCD</strong></h2>
<table border="0" cellspacing="0">
<colgroup width="85"></colgroup>
<colgroup width="523"></colgroup>
<tbody>
<tr>
<td align="center" height="17" data-sheets-value="{ &quot;1&quot;: 2, &quot;2&quot;: &quot;SCD type&quot;}"><b><span style="font-family: Liberation Serif;">SCD type</span></b></td>
<td align="center" data-sheets-value="{ &quot;1&quot;: 2, &quot;2&quot;: &quot;Use case scenarios&quot;}"><b><span style="font-family: Liberation Serif;">Use case scenarios</span></b></td>
</tr>
<tr>
<td align="left" height="17" data-sheets-value="{ &quot;1&quot;: 2, &quot;2&quot;: &quot;SCD type 0&quot;}"><span style="font-family: Liberation Serif;">SCD type 0</span></td>
<td align="left" data-sheets-value="{ &quot;1&quot;: 2, &quot;2&quot;: &quot;Durable data like constants, date dimensions&quot;}">Устойчивые данные, такие как константы, измерения по датам</td>
</tr>
<tr>
<td align="left" height="17" data-sheets-value="{ &quot;1&quot;: 2, &quot;2&quot;: &quot;SCD type 1&quot;}"><span style="font-family: Liberation Serif;">SCD type 1</span></td>
<td align="left" data-sheets-value="{ &quot;1&quot;: 2, &quot;2&quot;: &quot;Only current version of truth available, no need for historical data&quot;}">Только текущая версия данных (истина на данный момент), нет необходимости в исторических данных</td>
</tr>
<tr>
<td align="left" height="17" data-sheets-value="{ &quot;1&quot;: 2, &quot;2&quot;: &quot;SCD type 2&quot;}"><span style="font-family: Liberation Serif;">SCD type 2</span></td>
<td align="left" data-sheets-value="{ &quot;1&quot;: 2, &quot;2&quot;: &quot;Need historical versions of data and the periods during which they were current&quot;}">Необходимость в исторических версиях данных и периодах, в течение которых они были актуальны</td>
</tr>
<tr>
<td align="left" height="17" data-sheets-value="{ &quot;1&quot;: 2, &quot;2&quot;: &quot;SCD type 3&quot;}"><span style="font-family: Liberation Serif;">SCD type 3</span></td>
<td align="left" data-sheets-value="{ &quot;1&quot;: 2, &quot;2&quot;: &quot;Need for current data and the previous last value (alternate reality)&quot;}">Необходимость в текущих данных и предыдущем последнем значении (альтернативная реальность)</td>
</tr>
<tr>
<td align="left" height="32" data-sheets-value="{ &quot;1&quot;: 2, &quot;2&quot;: &quot;SCD type 4&quot;}"><span style="font-family: Liberation Serif;">SCD type 4</span></td>
<td align="left" data-sheets-value="{ &quot;1&quot;: 2, &quot;2&quot;: &quot;Used when a group of attributes in a dimension rapidly changes and is split off to a mini–dimension (rapidly changing monster dimension.)&quot;}">Используется, когда группа атрибутов в измерении быстро изменяется и выделяется в мини-измерение (быстро изменяющееся &#171;монстр-измерение&#187;)</td>
</tr>
<tr>
<td align="left" height="32" data-sheets-value="{ &quot;1&quot;: 2, &quot;2&quot;: &quot;SCD type 5&quot;}"><span style="font-family: Liberation Serif;">SCD type 5</span></td>
<td align="left" data-sheets-value="{ &quot;1&quot;: 2, &quot;2&quot;: &quot;Rarely used - to accurately preserve historical attribute values, plus report historical facts according to current attribute values; SCD 5 is equivalent to SCD 1 + SCD 4&quot;}">Редко используется — для точного сохранения исторических значений атрибутов и создания отчетов с учетом текущих значений атрибутов; SCD 5 эквивалентен SCD 1 + SCD 4</td>
</tr>
<tr>
<td align="left" height="32" data-sheets-value="{ &quot;1&quot;: 2, &quot;2&quot;: &quot;SCD type 6&quot;}"><span style="font-family: Liberation Serif;">SCD type 6</span></td>
<td align="left" data-sheets-value="{ &quot;1&quot;: 2, &quot;2&quot;: &quot;Rarely used - Unpredictable Changes with Single-Version Overlay; SCD 6 is equivalent to SCD 1 + SCD 2 + SCD 3&quot;}">Редко используется — непредсказуемые изменения с наложением одной версии; SCD 6 эквивалентен SCD 1 + SCD 2 + SCD 3</td>
</tr>
<tr>
<td align="left" height="17" data-sheets-value="{ &quot;1&quot;: 2, &quot;2&quot;: &quot;SCD type 7&quot;}"><span style="font-family: Liberation Serif;">SCD type 7</span></td>
<td align="left" data-sheets-value="{ &quot;1&quot;: 2, &quot;2&quot;: &quot;Rarely used - Hybrid technique that supports both as-was and as-is reporting&quot;}">Редко используется — гибридная техника, поддерживающая как &#171;как было&#187; (as-was), так и &#171;как есть&#187; (as-is) отчетность</td>
</tr>
</tbody>
</table>
<h3><strong>SCD Тип 0</strong></h3>
<p>Бывают ситуации, когда вы игнорируете любые изменения. Например, когда сотрудник присоединяется к организации, есть присоединенные связанные атрибуты, такие как присоединенное назначение и дата присоединения и т. д., которые не должны меняться со временем.</p>
<p>Ниже приведен пример для типа 0 медленно изменяющихся измерений в хранилище данных.</p>
<p><a href="https://datatalks.ru/wp-content/uploads/2025/01/type_0_slowly_changing_dimensions_in_data_warehous.png"><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-692" src="https://datatalks.ru/wp-content/uploads/2025/01/type_0_slowly_changing_dimensions_in_data_warehous.png" alt="" width="890" height="184" srcset="https://datatalks.ru/wp-content/uploads/2025/01/type_0_slowly_changing_dimensions_in_data_warehous.png 890w, https://datatalks.ru/wp-content/uploads/2025/01/type_0_slowly_changing_dimensions_in_data_warehous-300x62.png 300w, https://datatalks.ru/wp-content/uploads/2025/01/type_0_slowly_changing_dimensions_in_data_warehous-768x159.png 768w, https://datatalks.ru/wp-content/uploads/2025/01/type_0_slowly_changing_dimensions_in_data_warehous-450x93.png 450w, https://datatalks.ru/wp-content/uploads/2025/01/type_0_slowly_changing_dimensions_in_data_warehous-780x161.png 780w" sizes="(max-width: 890px) 100vw, 890px" /></a></p>
<p>В приведенном выше измерении «Клиент» FirstDesignation, JoinedDate и DateFirstPurchase — это атрибуты, которые не будут обновляться, что соответствует SCD типа 0.</p>
<h3><strong>SCD Тип 1</strong></h3>
<p>В SCD типа 1 вы просто перезаписываете данные в измерениях. Могут быть ситуации, когда у вас нет всех данных, когда запись инициируется в измерении. Например, когда инициируется запись клиента, вы можете не получить все атрибуты. Поэтому, когда запись клиента инициируется в рабочей базе данных, в записях клиентов будут пустые или нулевые записи. После выполнения ETL эти пустые записи будут созданы в хранилище данных. После того, как эти атрибуты будут заполнены в рабочих базах данных, это должно быть обновлено в хранилище данных.</p>
<p>SCD типа 1 определяют, являются ли существующие атрибуты нулевыми, и вы получаете значение из рабочей таблицы.</p>
<p><a href="https://datatalks.ru/wp-content/uploads/2025/01/type_1_slowly_changing_dimensions_in_data_warehous.png"><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-696" src="https://datatalks.ru/wp-content/uploads/2025/01/type_1_slowly_changing_dimensions_in_data_warehous.png" alt="" width="801" height="185" srcset="https://datatalks.ru/wp-content/uploads/2025/01/type_1_slowly_changing_dimensions_in_data_warehous.png 801w, https://datatalks.ru/wp-content/uploads/2025/01/type_1_slowly_changing_dimensions_in_data_warehous-300x69.png 300w, https://datatalks.ru/wp-content/uploads/2025/01/type_1_slowly_changing_dimensions_in_data_warehous-768x177.png 768w, https://datatalks.ru/wp-content/uploads/2025/01/type_1_slowly_changing_dimensions_in_data_warehous-450x104.png 450w, https://datatalks.ru/wp-content/uploads/2025/01/type_1_slowly_changing_dimensions_in_data_warehous-780x180.png 780w" sizes="(max-width: 801px) 100vw, 801px" /></a></p>
<p>В приведенной выше таблице Customer Dimension AnnualIncome клиентов <strong>CustomerKey</strong> 11015 и 11019 равны NULL. Когда эти записи обновляются в операционной базе данных, эти значения должны обновляться в хранилище данных без учета того, что это исторические значения.</p>
<h3><strong>SCD Тип 2</strong></h3>
<p>Тип 2 Медленно изменяющиеся измерения в хранилище данных — это самое популярное измерение, которое используется в хранилище данных. Как мы уже обсуждали, хранилище данных используется для анализа данных. Если вам нужно проанализировать данные, вам нужно учесть исторические аспекты данных. Давайте посмотрим, как мы можем реализовать SCD Тип 2.</p>
<p>Для SCD типа 2 нам необходимо включить еще три атрибута, такие как <strong>StartDate</strong>, <strong>EndDate</strong> и <strong>IsCurrent</strong>, как показано ниже.</p>
<p><a href="https://datatalks.ru/wp-content/uploads/2025/01/type_2_slowly_changing_dimensions_in_data_warehous.png"><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-697" src="https://datatalks.ru/wp-content/uploads/2025/01/type_2_slowly_changing_dimensions_in_data_warehous.png" alt="" width="886" height="96" srcset="https://datatalks.ru/wp-content/uploads/2025/01/type_2_slowly_changing_dimensions_in_data_warehous.png 886w, https://datatalks.ru/wp-content/uploads/2025/01/type_2_slowly_changing_dimensions_in_data_warehous-300x33.png 300w, https://datatalks.ru/wp-content/uploads/2025/01/type_2_slowly_changing_dimensions_in_data_warehous-768x83.png 768w, https://datatalks.ru/wp-content/uploads/2025/01/type_2_slowly_changing_dimensions_in_data_warehous-450x49.png 450w, https://datatalks.ru/wp-content/uploads/2025/01/type_2_slowly_changing_dimensions_in_data_warehous-780x85.png 780w" sizes="(max-width: 886px) 100vw, 886px" /></a></p>
<p>В приведенном выше измерении клиента есть две записи, и предположим, что клиент, <strong>CustomerCode</strong> которого — AW00011012, был повышен до старшего руководства. Однако, если вы просто обновите запись новым значением, вы не увидите предыдущие записи. Поэтому будет создана новая запись с новым <strong>CustomerKey</strong> и новым <strong>Designation</strong>. Однако другие атрибуты останутся прежними.</p>
<p><a href="https://datatalks.ru/wp-content/uploads/2025/01/implementation_of_type_2_slowly_changing_dimension.png"><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-698" src="https://datatalks.ru/wp-content/uploads/2025/01/implementation_of_type_2_slowly_changing_dimension.png" alt="" width="930" height="129" srcset="https://datatalks.ru/wp-content/uploads/2025/01/implementation_of_type_2_slowly_changing_dimension.png 930w, https://datatalks.ru/wp-content/uploads/2025/01/implementation_of_type_2_slowly_changing_dimension-300x42.png 300w, https://datatalks.ru/wp-content/uploads/2025/01/implementation_of_type_2_slowly_changing_dimension-768x107.png 768w, https://datatalks.ru/wp-content/uploads/2025/01/implementation_of_type_2_slowly_changing_dimension-450x62.png 450w, https://datatalks.ru/wp-content/uploads/2025/01/implementation_of_type_2_slowly_changing_dimension-780x108.png 780w" sizes="(max-width: 930px) 100vw, 930px" /></a></p>
<p>Как вы можете видеть на рисунке выше, <strong>CustomerCode</strong> AW00011012 имеет новую запись с кодом 11013. Все новые транзакции будут связаны с <strong>CustomerKey</strong> 11013, в то время как предыдущие транзакции связаны с <strong>CustomerKey</strong> 11012. Этот механизм помогает сохранить исторический аспект клиента, как показано в запросе ниже.</p><pre class="urvanov-syntax-highlighter-plain-tag">SELECT
    C.Designation,
    SUM(SalesAmount) AS SalesAmount,
    SUM(TotalProductCost) AS TotalProductCost 
FROM FactInternetSales F
INNER JOIN Dim_Customer C ON F.CustomerKey = C.CustomerKey
GROUP BY C.Designation</pre><p>После выполнения запроса будут получены следующие результаты.</p>
<p><a href="https://datatalks.ru/wp-content/uploads/2025/01/sample_dataset_for_the_type_2_scd.png"><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-699" src="https://datatalks.ru/wp-content/uploads/2025/01/sample_dataset_for_the_type_2_scd.png" alt="" width="464" height="107" srcset="https://datatalks.ru/wp-content/uploads/2025/01/sample_dataset_for_the_type_2_scd.png 464w, https://datatalks.ru/wp-content/uploads/2025/01/sample_dataset_for_the_type_2_scd-300x69.png 300w, https://datatalks.ru/wp-content/uploads/2025/01/sample_dataset_for_the_type_2_scd-450x104.png 450w" sizes="(max-width: 464px) 100vw, 464px" /></a></p>
<p>Как вы можете видеть, обозначение управления можно увидеть в приведенном выше результате, что означает, что оно охватывает исторические аспекты. Тип 2 SCD является одной из реализаций, где вы не можете избежать суррогатных ключей в размерных таблицах в хранилище данных.</p>
<h3><strong>SCD Тип 3</strong></h3>
<p>Тип 3 Медленно изменяющееся измерение в хранилище данных — это простая реализация, где история будет храниться в дополнительном столбце. Если мы свяжем тот же сценарий, который мы обсуждали в Типе 2 SCD, с Типом 3 SCD, измерение клиента будет выглядеть следующим образом.</p>
<p><a href="https://datatalks.ru/wp-content/uploads/2025/01/type_3_scd.png"><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-700" src="https://datatalks.ru/wp-content/uploads/2025/01/type_3_scd.png" alt="" width="834" height="92" srcset="https://datatalks.ru/wp-content/uploads/2025/01/type_3_scd.png 834w, https://datatalks.ru/wp-content/uploads/2025/01/type_3_scd-300x33.png 300w, https://datatalks.ru/wp-content/uploads/2025/01/type_3_scd-768x85.png 768w, https://datatalks.ru/wp-content/uploads/2025/01/type_3_scd-450x50.png 450w, https://datatalks.ru/wp-content/uploads/2025/01/type_3_scd-780x86.png 780w" sizes="(max-width: 834px) 100vw, 834px" /></a></p>
<p>Как вы можете видеть, исторические аспекты данных сохраняются в виде другого столбца. Однако этот метод не будет масштабируемым, если вы хотите сохранить историю. Кроме того, эта техника позволит сохранить только последнюю версию истории, в отличие от SCD типа 2.</p>
<p>Обычно это лучше подходит для внедрения изменений имени сотрудника. В некоторых случаях женщины-сотрудницы меняют свои имена после замужества. В таких ситуациях вы можете использовать SCD типа 3, поскольку эти типы изменений не будут происходить быстро.</p>
<h3><strong>SCD Тип 4</strong></h3>
<p>Как мы обсуждали в SCD типа 2, мы сохраняем историю, добавляя другую версию строки в измерение. Однако, если изменения быстрые по своей природе, SCD типа 2 не будет масштабируемым.</p>
<p>Например, предположим, что мы хотим сохранить тип риска клиента в зависимости от его предыдущего платежа. Поскольку это атрибут, связанный с клиентом, он должен храниться в измерении клиента. Это означает, что каждый месяц будет новая версия записи клиента. Если у вас 1000 клиентов, вы просматриваете 12 000 записей в месяц. Как вы можете себе представить, эти медленно меняющиеся измерения в хранилище данных не масштабируются.</p>
<p>Ниже приведена взаимосвязь между таблицами «Факт» и «Клиентское измерение».</p>
<p><a href="https://datatalks.ru/wp-content/uploads/2025/01/schema_design_before_implementing_type_4_scd.png"><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-701" src="https://datatalks.ru/wp-content/uploads/2025/01/schema_design_before_implementing_type_4_scd.png" alt="" width="1017" height="447" srcset="https://datatalks.ru/wp-content/uploads/2025/01/schema_design_before_implementing_type_4_scd.png 1017w, https://datatalks.ru/wp-content/uploads/2025/01/schema_design_before_implementing_type_4_scd-300x132.png 300w, https://datatalks.ru/wp-content/uploads/2025/01/schema_design_before_implementing_type_4_scd-768x338.png 768w, https://datatalks.ru/wp-content/uploads/2025/01/schema_design_before_implementing_type_4_scd-450x198.png 450w, https://datatalks.ru/wp-content/uploads/2025/01/schema_design_before_implementing_type_4_scd-780x343.png 780w" sizes="(max-width: 1017px) 100vw, 1017px" /></a></p>
<p>SCD Type 4 вводится для исправления этой проблемы. В этом методе быстро меняющийся столбец выносится из измерения и перемещается в новую таблицу измерений. Это новое измерение связано с таблицей фактов, как показано на диаграмме ниже.</p>
<p><a href="https://datatalks.ru/wp-content/uploads/2025/01/schema_design_after_implementing_type_4_scd.png"><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-702" src="https://datatalks.ru/wp-content/uploads/2025/01/schema_design_after_implementing_type_4_scd.png" alt="" width="1048" height="503" srcset="https://datatalks.ru/wp-content/uploads/2025/01/schema_design_after_implementing_type_4_scd.png 1048w, https://datatalks.ru/wp-content/uploads/2025/01/schema_design_after_implementing_type_4_scd-300x144.png 300w, https://datatalks.ru/wp-content/uploads/2025/01/schema_design_after_implementing_type_4_scd-1024x491.png 1024w, https://datatalks.ru/wp-content/uploads/2025/01/schema_design_after_implementing_type_4_scd-768x369.png 768w, https://datatalks.ru/wp-content/uploads/2025/01/schema_design_after_implementing_type_4_scd-450x216.png 450w, https://datatalks.ru/wp-content/uploads/2025/01/schema_design_after_implementing_type_4_scd-780x374.png 780w" sizes="(max-width: 1048px) 100vw, 1048px" /></a></p>
<p>С помощью вышеописанной реализации медленно изменяющихся измерений типа 4 в хранилище данных вы устраняете ненужный объем в основном измерении. Однако у вас все еще есть возможности для выполнения необходимого анализа.</p>
<h3><strong>SCD Тип 6</strong></h3>
<p>Медленно изменяющиеся измерения типа 6 в хранилище данных представляют собой комбинацию SCD типа 2 и типа 3. Это означает, что в реализации SCD типа 6 оба столбца являются строками.</p>
<p><a href="https://datatalks.ru/wp-content/uploads/2025/01/sample_dataset_for_type_6_scd.png"><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-703" src="https://datatalks.ru/wp-content/uploads/2025/01/sample_dataset_for_type_6_scd.png" alt="" width="1155" height="150" srcset="https://datatalks.ru/wp-content/uploads/2025/01/sample_dataset_for_type_6_scd.png 1155w, https://datatalks.ru/wp-content/uploads/2025/01/sample_dataset_for_type_6_scd-300x39.png 300w, https://datatalks.ru/wp-content/uploads/2025/01/sample_dataset_for_type_6_scd-1024x133.png 1024w, https://datatalks.ru/wp-content/uploads/2025/01/sample_dataset_for_type_6_scd-768x100.png 768w, https://datatalks.ru/wp-content/uploads/2025/01/sample_dataset_for_type_6_scd-450x58.png 450w, https://datatalks.ru/wp-content/uploads/2025/01/sample_dataset_for_type_6_scd-780x101.png 780w" sizes="(max-width: 1155px) 100vw, 1155px" /></a></p>
<p>С этой реализацией вы можете еще больше улучшить аналитические возможности хранилища данных. Если вы хотите найти анализ между текущей и исторической оккупацией, вы можете использовать следующий запрос.</p><pre class="urvanov-syntax-highlighter-plain-tag">SELECT
    C.Occupation,
    C.CurrentOccupation,
    SUM(SalesAmount) AS SalesAmount,
    SUM(TotalProductCost) AS TotalProductCost 
FROM FactInternetSales F
INNER JOIN Dim_Customer C ON F.CustomerKey = C.CustomerKey
GROUP BY C.Occupation,C.CurrentOccupation</pre><p>Приведенный выше запрос даст следующий результат:</p>
<p><a href="https://datatalks.ru/wp-content/uploads/2025/01/results_with_type_6_scd.png"><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-704" src="https://datatalks.ru/wp-content/uploads/2025/01/results_with_type_6_scd.png" alt="" width="619" height="136" srcset="https://datatalks.ru/wp-content/uploads/2025/01/results_with_type_6_scd.png 619w, https://datatalks.ru/wp-content/uploads/2025/01/results_with_type_6_scd-300x66.png 300w, https://datatalks.ru/wp-content/uploads/2025/01/results_with_type_6_scd-450x99.png 450w" sizes="(max-width: 619px) 100vw, 619px" /></a></p>
<p>Без Типа 6, медленно меняющихся измерений в хранилище данных, приходится использовать сложные запросы.</p>
<p>В SCD типа 6 можно использовать не только текущую профессию, но и первую профессию для проведения более глубокого анализа.</p>
<h1>Как устроено CDC (Change Data Capture)</h1>
<p><strong>Сбор измененных данных (Change Data Capture, CDC)</strong> — это процесс выявления и фиксации изменений, внесенных в данные в базе данных, а затем передача этих изменений в режиме реального времени в последующий процесс или систему.</p>
<p><strong>Почему это важно</strong></p>
<p>Фиксация всех изменений транзакций в исходной базе данных и их перенос в целевую базу данных в режиме реального времени позволяет синхронизировать системы и обеспечивает надежную репликацию данных и миграцию в облако без простоев.</p>
<p>CDC идеально подходит для современных облачных архитектур, поскольку это высокоэффективный способ перемещения данных по глобальной сети. И поскольку он перемещает данные в режиме реального времени, он также поддерживает аналитику и науку о данных в режиме реального времени.</p>
<h2>Три основных подхода CDC (Change Data Capture Methods)</h2>
<p><strong>1. Log-based CDC (CDC на основе журнала).</strong> Это наиболее эффективный способ внедрения CDC. Когда новая транзакция попадает в базу данных, она регистрируется в файле журнала без влияния на исходную систему. И вы можете подобрать эти изменения, а затем переместить их из журнала.<br />
Блок-схема, показывающая изменения данных в исходной базе данных (удаление, обновление, вставка), регистрируемые майнером журнала транзакций и применяемые к целевой системе с метками времени и суммами для каждой операции.</p>
<p><a href="https://datatalks.ru/wp-content/uploads/2025/01/Transaction_Log_CDC.png"><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-669" src="https://datatalks.ru/wp-content/uploads/2025/01/Transaction_Log_CDC.png" alt="" width="1014" height="662" srcset="https://datatalks.ru/wp-content/uploads/2025/01/Transaction_Log_CDC.png 1014w, https://datatalks.ru/wp-content/uploads/2025/01/Transaction_Log_CDC-300x196.png 300w, https://datatalks.ru/wp-content/uploads/2025/01/Transaction_Log_CDC-768x501.png 768w, https://datatalks.ru/wp-content/uploads/2025/01/Transaction_Log_CDC-450x294.png 450w, https://datatalks.ru/wp-content/uploads/2025/01/Transaction_Log_CDC-780x509.png 780w" sizes="(max-width: 1014px) 100vw, 1014px" /></a></p>
<p><strong>2. Query-based CDC (CDC на основе запросов) / Timestamp-Based CDC.</strong> Здесь вы запрашиваете данные в источнике, чтобы получить изменения. Этот подход более инвазивный для исходных систем, потому что вам нужно что-то вроде временной метки в самих данных.</p>
<p>Этот метод подразумевает добавление в таблицы выделенного столбца, который отражает время последнего изменения (например, <code> LAST_MODIFIED</code>или <code> LAST_UPDATED</code>). Последующие системы могут затем запросить это поле, чтобы извлечь записи, обновленные с момента их последней проверки.</p>
<p><a href="https://datatalks.ru/wp-content/uploads/2025/01/timestamp_based_cdc.png"><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-674" src="https://datatalks.ru/wp-content/uploads/2025/01/timestamp_based_cdc.png" alt="" width="833" height="403" srcset="https://datatalks.ru/wp-content/uploads/2025/01/timestamp_based_cdc.png 833w, https://datatalks.ru/wp-content/uploads/2025/01/timestamp_based_cdc-300x145.png 300w, https://datatalks.ru/wp-content/uploads/2025/01/timestamp_based_cdc-768x372.png 768w, https://datatalks.ru/wp-content/uploads/2025/01/timestamp_based_cdc-450x218.png 450w, https://datatalks.ru/wp-content/uploads/2025/01/timestamp_based_cdc-780x377.png 780w" sizes="(max-width: 833px) 100vw, 833px" /></a></p>
<p><strong>3. Trigger-based CDC (CDC на основе триггера).</strong> При этом подходе вы изменяете исходное приложение для запуска записи в таблицу изменений, а затем перемещаете ее. Такой подход снижает производительность базы данных, поскольку требует множественных записей каждый раз, когда строка обновляется, вставляется или удаляется.</p>
<p><a href="https://datatalks.ru/wp-content/uploads/2025/01/Trigger_based_CDC.png"><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-670" src="https://datatalks.ru/wp-content/uploads/2025/01/Trigger_based_CDC.png" alt="" width="1059" height="559" srcset="https://datatalks.ru/wp-content/uploads/2025/01/Trigger_based_CDC.png 1059w, https://datatalks.ru/wp-content/uploads/2025/01/Trigger_based_CDC-300x158.png 300w, https://datatalks.ru/wp-content/uploads/2025/01/Trigger_based_CDC-1024x541.png 1024w, https://datatalks.ru/wp-content/uploads/2025/01/Trigger_based_CDC-768x405.png 768w, https://datatalks.ru/wp-content/uploads/2025/01/Trigger_based_CDC-450x238.png 450w, https://datatalks.ru/wp-content/uploads/2025/01/Trigger_based_CDC-780x412.png 780w" sizes="(max-width: 1059px) 100vw, 1059px" /></a></p>
<h2>Подборка видео про CDC</h2>
<h3>Change Data Capture (CDC) Explained (with examples)</h3>
<p><iframe title="Change Data Capture (CDC) Explained (with examples)" width="1170" height="658" src="https://www.youtube.com/embed/5KN_feUhtTM?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe></p>
<h3>Stream your PostgreSQL changes into Kafka with Debezium</h3>
<p><iframe title="Stream your PostgreSQL changes into Kafka with Debezium" width="1170" height="658" src="https://www.youtube.com/embed/YZRHqRznO-o?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe></p>
<p>Сообщение <a href="https://datatalks.ru/incremental-data-refresh-sql-patterns/">Инкрементальное обновление данных &#8212; Incremental Data Refresh</a> появились сначала на <a href="https://datatalks.ru">DataTalks.RU. Data Engineering / DWH / Data Pipeline</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://datatalks.ru/incremental-data-refresh-sql-patterns/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
