<?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>Slowly Changing Dimensions - DataTalks.RU. Data Engineering / DWH / Data Pipeline</title>
	<atom:link href="https://datatalks.ru/tag/slowly-changing-dimensions/feed/" rel="self" type="application/rss+xml" />
	<link>https://datatalks.ru/tag/slowly-changing-dimensions/</link>
	<description>RoadMap для инженера данных. Дорожная карта по инструментам Data Engineer</description>
	<lastBuildDate>Sat, 11 Oct 2025 09:23:21 +0000</lastBuildDate>
	<language>ru-RU</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.0.1</generator>

<image>
	<url>https://datatalks.ru/wp-content/uploads/2024/12/cropped-logo_datatalks-32x32.png</url>
	<title>Slowly Changing Dimensions - DataTalks.RU. Data Engineering / DWH / Data Pipeline</title>
	<link>https://datatalks.ru/tag/slowly-changing-dimensions/</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Перевод 7 Главы &#8212; Dimensional Modeling (Data Vault 2.0)</title>
		<link>https://datatalks.ru/chapter-7-data-vault-2-0-dimensional-modeling/</link>
					<comments>https://datatalks.ru/chapter-7-data-vault-2-0-dimensional-modeling/#comments</comments>
		
		<dc:creator><![CDATA[Data Engineer (Admin)]]></dc:creator>
		<pubDate>Thu, 03 Jul 2025 09:06:35 +0000</pubDate>
				<category><![CDATA[Data Architecture / Data Modeling]]></category>
		<category><![CDATA[Data Vault 2.0]]></category>
		<category><![CDATA[Conformed Dimensions]]></category>
		<category><![CDATA[Dimension Design]]></category>
		<category><![CDATA[Dimensional Modeling]]></category>
		<category><![CDATA[Multiple Stars]]></category>
		<category><![CDATA[SCD]]></category>
		<category><![CDATA[Slowly Changing Dimensions]]></category>
		<category><![CDATA[Snowflake Design]]></category>
		<category><![CDATA[Многомерное моделирование]]></category>
		<guid isPermaLink="false">https://datatalks.ru/?p=1729</guid>

					<description><![CDATA[<p>Перевод книги &#171;Building a Scalable Data Warehouse with Data Vault 2.0&#187; подготовлен автором сайта ГЛАВА 7. Многомерное моделирование (Dimensional Modeling) Аннотация Моделирование Data Vault не является заменой Dimensional Modeling, которое является отраслевым стандартом для определения витрины данных (уровня, используемого для предоставления данных конечному пользователю). Поскольку данная книга предназначена для охвата всего процесса построения хранилища данных [&#8230;]</p>
<p>Сообщение <a href="https://datatalks.ru/chapter-7-data-vault-2-0-dimensional-modeling/">Перевод 7 Главы &#8212; Dimensional Modeling (Data Vault 2.0)</a> появились сначала на <a href="https://datatalks.ru">DataTalks.RU. Data Engineering / DWH / Data Pipeline</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p><em>Перевод книги &#171;Building a Scalable Data Warehouse with Data Vault 2.0&#187; подготовлен автором сайта</em></p>
<h1>ГЛАВА 7. Многомерное моделирование (Dimensional Modeling)</h1>
<h2>Аннотация</h2>
<p>Моделирование Data Vault не является заменой Dimensional Modeling, которое является отраслевым стандартом для определения витрины данных (уровня, используемого для предоставления данных конечному пользователю). Поскольку данная книга предназначена для охвата всего процесса построения хранилища данных от начала до конца, она также охватывает и Dimensional Modeling.</p>
<p>Первая часть этой главы сосредоточена на базовых сущностях <strong>Dimensional Modeling</strong> — фактовых сущностях и размерных сущностях.</p>
<ul>
<li><strong>Fact Entities (Сущности фактов)</strong> &#8212; хранят измерения, метрики или факты бизнес-процесса (иными словами содержат числовые показатели бизнес-операций &#8212; факты и ключи к соответствующим таблицам размерностей).</li>
<li><strong>Dimension Entities (Cущности измерений)</strong> &#8212; содержат описательные атрибуты для фактов.</li>
</ul>
<p>Будут рассмотрены различные типы размерностей, такие как медленно изменяющиеся измерения, а также способы выполнения запросов к данным из многомерной модели. Вторая часть этой главы объясняет, как работать с несколькими звёздными схемами, особенно с использованием согласованных измерений. Последняя часть сосредоточена на техниках многомерного проектирования и представляет снежинку и схему &#171;Звезда&#187; как частный случай схемы снежинки.</p>
<p><strong>Ключевые слова</strong></p>
<ul>
<li>Dimension modeling (Многомерное моделирование)</li>
<li>Fact Entities (Фактовые сущности)</li>
<li>Техники проектирования</li>
<li>Snowflake Schemas (Схема &#171;Снежинка&#187;)</li>
<li>Star Schemas (Схема &#171;Звезда&#187;)</li>
</ul>
<p>Наилучшее применение <strong>моделирования Data Vault 2.0</strong> — это уровень корпоративного хранилища данных. Оно было специально разработано для этой цели и является оптимальным выбором, когда требуется расширяемая, функционально-ориентированная модель, позволяющая отслеживать историю и проводить аудит, а также интегрируемая в среды реального времени и NoSQL.</p>
<p>Однако большинство бизнес-пользователей не знакомы с моделированием Data Vault 2.0. Во многих случаях конечным пользователям сначала требуется надлежащее обучение, чтобы они могли напрямую обращаться к <strong>Raw Data Vault</strong> или <strong>Business Vault</strong>, которые моделируются по тем же принципам. Им также необходимо понимать, как соединять многочисленные сущности, чтобы получать ценные и пригодные для использования сырые данные, которые могут быть обработаны в полезную информацию. Поэтому прямой доступ к уровню корпоративного хранилища данных ограничен опытными пользователями, которые хотят использовать собственные запросы и которым нужны сырые данные для этих целей. Большинство же конечных пользователей будут использовать информационные витрины для доступа к подготовленной информации, которую они могут напрямую использовать для выполнения своих задач.</p>
<p>Ещё одна проблема заключается в том, что большинство фронтенд-инструментов, используемых бизнесом для анализа информации, предоставляемой хранилищем данных, не могут напрямую использовать структуры Data Vault. Например, построение <strong>OLAP-куба в Microsoft SQL Server Analysis Services (SSAS)</strong> лучше всего работает, если источник данных смоделирован в виде звёздной схемы, которая является реляционной версией Dimension модели.</p>
<p>Многомерное моделирование было представлено широкой аудитории в индустрии хранилищ данных Ральфом Кимбаллом в 1997 году. Однако он не был его изобретателем. Термины &#171;размерности&#187; и &#171;факты&#187;, которые являются основными конструкциями в многомерном моделировании, восходят к 1960-м годам, когда проводился совместный исследовательский проект между Дартмутским университетом и General Mills. Первая размерная модель (dimension model) была представлена компаниями AC Nielsen и IRI для описания ранних многомерных витрин данных для данных о розничных продажах. Но именно серия книг Ральфа Кимбалла способствовала популяризации размерного/многомерного моделирования в индустрии хранилищ данных, и оно стало стандартом моделирования. В результате многомерное моделирование поддерживается многими фронтенд-инструментами сегодня. Поэтому оно хорошо известно и понятно конечным пользователям и является оптимальным выбором для моделирования информационных витрин, которые служат в качестве фронтенд-слоя.</p>
<h1>Введение</h1>
<p><strong>Системы хранилищ данных</strong> поддерживают бизнес, помогая решать аналитические задачи — то есть, отвечать на вопросы, касающиеся бизнес-процессов. Например, бизнес-пользователи в авиапромышленности могут захотеть проанализировать следующие вопросы:</p>
<ul>
<li>Как изменялась степень загрузки на определённых рейсах за последний финансовый год?</li>
<li>Какова эффективность нашей бонусной программы для часто летающих пассажиров в отношении продаж?</li>
<li>Кто наши часто летающие пассажиры? Каков их средний объём продаж?</li>
</ul>
<p>Такие вопросы не касаются отдельных транзакций, а связаны с <strong>метриками (measurement)</strong> по всему процессу. Обычно для этого метрики по отдельным транзакциям агрегируются (например, суммируются или усредняются). Ещё одной характеристикой аналитических запросов является то, что не требуется модификация данных в операционных системах для получения ответов.</p>
<p>По всем этим причинам имеет смысл организовать данные в слое информационных витрин (information mart) таким образом, чтобы бизнес-пользователи могли быстро агрегировать информацию, а не быстро её модифицировать. Именно поэтому <strong>размерная модель (dimensional model)</strong> проектируется с учётом того, как измеряются данные. Поскольку <strong>метрики (measurement)</strong> часто основаны на бизнес-процессе, сам бизнес-процесс должен быть центром моделирования. Кроме того, необходим контекст, чтобы придать метрикам смысл, например, чтобы упорядочить метрики по аэропортам, как показано в Таблице 7.1.</p>
<p><strong>Таблица 7.1 Пропорция пассажиров, работников, посетителей и провожающих/встречающих в выбранных аэропортах (с использованием искусственных данных)</strong></p>
<p><a href="https://datatalks.ru/wp-content/uploads/2025/07/table_7_1.png"><img fetchpriority="high" decoding="async" class="aligncenter size-full wp-image-1780" src="https://datatalks.ru/wp-content/uploads/2025/07/table_7_1.png" alt="" width="807" height="689" srcset="https://datatalks.ru/wp-content/uploads/2025/07/table_7_1.png 807w, https://datatalks.ru/wp-content/uploads/2025/07/table_7_1-300x256.png 300w, https://datatalks.ru/wp-content/uploads/2025/07/table_7_1-768x656.png 768w, https://datatalks.ru/wp-content/uploads/2025/07/table_7_1-450x384.png 450w, https://datatalks.ru/wp-content/uploads/2025/07/table_7_1-780x666.png 780w" sizes="(max-width: 807px) 100vw, 807px" /></a></p>
<p>В этой таблице представлено одна метрика — число лиц, которые были либо пассажирами, либо провожающими/встречающими, либо работниками, либо посетителями аэропорта, выраженное в виде соотношения между этими четырьмя ролями. Четыре роли — это первое измерение (dimension), а аэропорт — второе. Обе размерности охватывают данные и определяют уровень детализации для подсчёта лиц.</p>
<p>Эти две фундаментальные концепции — <strong>метрики (measurements)</strong> и <strong>контекст (context)</strong> &#8212; являются основой размерного моделирования.</p>
<h1>Схема &#171;Звезда&#187; (Star Schemas)</h1>
<p>Когда размерная модель реализована в реляционной базе данных, она называется <strong>звёздной схемой</strong>. Это объясняется тем, что размерная модель реляционных таблиц при взгляде сверху выглядит как звезда (см. Рисунок 7.1).</p>
<p><strong>Рисунок 7.1 Пример схемы &#171;Звезда&#187; для посещений аэропортов (физическая реализация)</strong></p>
<p><a href="https://datatalks.ru/wp-content/uploads/2025/07/image_7_1_star_schema.png"><img decoding="async" class="aligncenter size-full wp-image-1787" src="https://datatalks.ru/wp-content/uploads/2025/07/image_7_1_star_schema.png" alt="" width="1027" height="798" srcset="https://datatalks.ru/wp-content/uploads/2025/07/image_7_1_star_schema.png 1027w, https://datatalks.ru/wp-content/uploads/2025/07/image_7_1_star_schema-300x233.png 300w, https://datatalks.ru/wp-content/uploads/2025/07/image_7_1_star_schema-1024x796.png 1024w, https://datatalks.ru/wp-content/uploads/2025/07/image_7_1_star_schema-768x597.png 768w, https://datatalks.ru/wp-content/uploads/2025/07/image_7_1_star_schema-450x350.png 450w, https://datatalks.ru/wp-content/uploads/2025/07/image_7_1_star_schema-780x606.png 780w" sizes="(max-width: 1027px) 100vw, 1027px" /></a></p>
<p>Исходный рисунок (в плохом качестве)</p>
<p><a href="https://datatalks.ru/wp-content/uploads/2025/07/image_7_1_star_schema_initial.png"><img decoding="async" class="aligncenter size-full wp-image-1789" src="https://datatalks.ru/wp-content/uploads/2025/07/image_7_1_star_schema_initial.png" alt="" width="881" height="943" srcset="https://datatalks.ru/wp-content/uploads/2025/07/image_7_1_star_schema_initial.png 881w, https://datatalks.ru/wp-content/uploads/2025/07/image_7_1_star_schema_initial-280x300.png 280w, https://datatalks.ru/wp-content/uploads/2025/07/image_7_1_star_schema_initial-768x822.png 768w, https://datatalks.ru/wp-content/uploads/2025/07/image_7_1_star_schema_initial-450x482.png 450w, https://datatalks.ru/wp-content/uploads/2025/07/image_7_1_star_schema_initial-780x835.png 780w" sizes="(max-width: 881px) 100vw, 881px" /></a></p>
<p>Модель на Рисунке 7.1 представляет модель, лежащую в основе данных Таблицы 7.1. В центре модели находится таблица фактов, окружённая четырьмя таблицами измерений.</p>
<p>Основное отличие схемы &#171;Звезда&#187; на Рисунке 7.1 от нормализованной модели в третьей нормальной форме (3NF), которая часто используется в операционных системах, заключается в том, что размерная модель обычно использует денормализованные таблицы, особенно:</p>
<ul>
<li><strong>Таблицы Фактов:</strong> таблица в центре этой схемы содержит метрики/меры/показатели бизнеса, которые в случае Рисунка 7.1 представляют собой транзакции полётов. Эти measurements, как правило, являются метриками, которые бизнес желает проанализировать.</li>
<li><strong>Таблицы Измерений:</strong> таблицы размерностей группируют факты по категориям и предоставляют дополнительные описательные атрибуты к этим категориям. Эти категории называются размерностями и помогают конечному пользователю ориентироваться в модели и выбирать только нужное подмножество данных для анализа.</li>
</ul>
<p>В дополнение к этим основным таблицам, в размерном моделировании часто используются и другие типы таблиц, например, <strong>связующие таблицы (bridge tables)</strong>. В большинстве случаев можно создать размерную модель, которая содержит тот же контент, что и модель в 3NF. Однако, будучи представленной как звёздная схема, она легче воспринимается бизнес-пользователями и оптимизирована для выполнения запросов.</p>
<p>Это связано с денормализацией, которая обычно происходит при преобразовании модели 3NF в размерную модель. Иерархии и справочники предобъединены, что требует от оптимизатора СУБД учитывать меньшее количество объединений и временных таблиц. Также становится проще агрегировать данные, поскольку все измерения уже содержатся в центральной таблице фактов. Некоторые редакции Microsoft SQL Server также поддерживают <strong>оптимизацию звёздного объединения (star join optimization)</strong>, функцию, которая значительно сокращает объём данных, считываемых с диска для ответа на запросы.</p>
<p>Следующие разделы более подробно объясняют основные сущности размерного моделирования и звёздных схем.</p>
<h2>Таблицы фактов (Fact Tables)</h2>
<p><strong>Таблицы Фактов</strong> содержат информацию о конкретных бизнес-процессах или событиях в рамках этих процессов. Примерами таких бизнес-процессов и событий являются рейсы, заказы, телефонные звонки или обращения к веб-сайту. Каждая запись в таблице фактов представляет одно из этих событий и предоставляет метрики, связанные с этим бизнес-событием. Обычно это числовые значения, которые количественно выражают, например, продолжительность рейса, время до взлета, количество отклонений от маршрута или сколько товаров было заказано и по какой цене. Эти значения называются фактами таблицы.</p>
<p>В других случаях таблицы фактов могут содержать отношения между бизнес-объектами, например, уровни запасов на определённые даты. Эти уровни запасов являются формой отношений, потому что они показывают, какой продукт доступен в каком складском расположении в определённый момент времени. Каждое такое отношение представлено в таблице фактов одной записью. На рисунке 7.2 показан пример таблицы фактов, представляющей рейс.</p>
<p><strong>Рисунок 7.2 Таблица фактов для рейсов (физическая модель)</strong></p>
<p><a href="https://datatalks.ru/wp-content/uploads/2025/07/image_7_2.jpeg"><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-1791" src="https://datatalks.ru/wp-content/uploads/2025/07/image_7_2.jpeg" alt="" width="358" height="675" srcset="https://datatalks.ru/wp-content/uploads/2025/07/image_7_2.jpeg 358w, https://datatalks.ru/wp-content/uploads/2025/07/image_7_2-159x300.jpeg 159w" sizes="(max-width: 358px) 100vw, 358px" /></a></p>
<p><strong>Таблица фактов содержит два разных типа столбцов:</strong></p>
<ul>
<li>Во-первых,<strong> внешние ключи на таблицы измерений,</strong> которые рассматриваются в следующем разделе. Сюда входят все четыре ссылки, которые являются частью составного первичного ключа, а также <code>TailNumberKey</code>, <code>CancelledKey</code> и <code>DivertedKey</code>.</li>
<li>Во-вторых, <strong>значения измерений, сами факты.</strong> Многие из них указывают продолжительность задержек, например, <code>DepartureDelay</code>, <code>WeatherDelay</code> или <code>SecurityDelay</code>. Другие показывают продолжительность подпроцессов, например, время руления при въезде и выезде, время в полёте и пройденное расстояние.</li>
</ul>
<p>Не все факты являются числовыми значениями, но именно числовые наиболее полезны для бизнес-пользователей, потому что их легко агрегировать по размерностям. Таблица фактов идентифицируется подмножеством внешних ключей к таблицам измерений. Это подмножество становится составным ключом, который представляет собой первичный ключ таблицы. Не все внешние ключи обязательно должны быть включены в первичный ключ, потому что во многих случаях размерность лишь описывает факт, но не идентифицирует его. В других случаях может потребоваться добавить ещё один идентифицирующий факт в первичный ключ фактовой таблицы, чтобы гарантировать уникальность, например, номер транзакции, такой как номер счёта или код бронирования.</p>
<p>Ввод ключей для уникальной идентификации строк в качестве первичного ключа таблицы фактов следует избегать, из-за необходимого объёма хранения для хранения значений ключей, а также из-за необходимости поддержки индекса. Сам индекс бесполезен, так как он не может быть использован конечным пользователем для идентификации отдельных фактов. Только в некоторых ограниченных случаях, в основном по техническим причинам, сгенерированный или производный ключ, используемый как первичный ключ, действительно имеет смысл.</p>
<p>Примером такой причины может быть требование со стороны бизнеса загружать идентичные строки в фактовую таблицу (например, при работе с историей) или необходимость перекрёстных ссылок с другими фактовыми таблицами.</p>
<h3><strong>Гранулярность таблицы фактов (Grain of a Fact Table)</strong></h3>
<p>Количество ссылок на измерения в таблице фактов определяет уровень детализации таблицы фактов. Этот уровень детализации называется <strong>гранулярностью (Grain)</strong>.</p>
<p>Хорошей практикой является сохранение уровня детализации как можно ниже, в идеале — на самом низком уровне, который предоставляет источник данных. Этот исходный уровень детализации также известен как атомарный уровень. Предоставление таких атомарных таблиц фактов бизнес-пользователям обеспечивает им наибольшую гибкость, потому что они могут агрегировать данные самостоятельно, исключая ненужные измерения из запроса и группируя данные по оставшимся измерениям.</p>
<p>Такой подход называется <strong>свёрткой (roll-up)</strong> и используется для обобщения данных по <strong>подмножеству измерений факта (subset of fact dimensions)</strong>. Однако, хранение таблиц фактов на самом низком уровне гранулярности не всегда осуществимо, если серверная инфраструктура не предоставляет достаточных ресурсов для хранения самого низкого уровня детализации. В этом случае предварительная агрегация данных до более высокого уровня детализации обеспечивает более быстрые ответы бизнес-пользователям при прямом запросе к таблицам фактов. Обратите внимание, что это утверждение уже не актуально при использовании многомерных OLAP-кубов, потому что они агрегируют данные внутри куба прозрачно для конечного пользователя.</p>
<h2>Таблицы размерностей/измерений (Dimension Tables)</h2>
<p><strong>Измерения/Размерности/Dimensions (а значит, и реляционные таблицы размерностей) предоставляют контекст для фактов.</strong> Они очень важны для понимания хранилища данных. Без измерений (dimensions) невозможно было бы понять метрики, предоставляемые таблицей фактов, потому что все метки и прочая описательная информация берутся из таблиц измерений. Как уже объяснялось в предыдущем разделе, они также используются для определения, как факты будут агрегироваться (сворачиваться). Кроме того, они могут использоваться для фильтрации фактов в соответствии с записью dimension или одним из её описательных атрибутов. Также возможно сортировать агрегированные метрики по измерению или одному из её атрибутов. На рисунке 7.3 показан пример таблицы размерности.</p>
<p><strong>Рисунок 7.3 Таблица измерений пассажиров (физическая модель)</strong></p>
<p><a href="https://datatalks.ru/wp-content/uploads/2025/07/image_7_3.jpeg"><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-1793" src="https://datatalks.ru/wp-content/uploads/2025/07/image_7_3.jpeg" alt="" width="245" height="470" srcset="https://datatalks.ru/wp-content/uploads/2025/07/image_7_3.jpeg 245w, https://datatalks.ru/wp-content/uploads/2025/07/image_7_3-156x300.jpeg 156w" sizes="(max-width: 245px) 100vw, 245px" /></a></p>
<p>В отличие от таблиц фактов, таблица измерения использует значение ключа <code>PassengerKey</code> в качестве первичного ключа таблицы. Это связано с тем, что этот ключ часто используется в таблице фактов, ссылающейся на таблицу измерения. Чтобы сократить объём необходимого хранилища и повысить производительность соединений, имеет смысл поступать именно так и избегать использования натурального ключа. В остальном этот ключ не имеет значения для бизнеса. В дополнение к этому техническому ключу <strong>Измерения (Dimensions)</strong> часто содержат бизнес-ключи, которые идентифицируют записи в <strong>таблице dimension</strong>. На рисунке 7.3 это атрибут <code>PassportNumber</code>. Записи часто представляют собой бизнес-объекты и изменения этих объектов в операционной системе. Хотя натуральный ключ для одного и того же бизнес-объекта остаётся неизменным, даже если описательные данные были изменены в операционной системе, ключ изменяется при каждом изменении данных. Этот эффект используется таблицей фактов для ссылки на версию данных, которая была активна в момент, когда произошло бизнес-событие. Хеш-ключ из модели Data Vault 2.0 используется в качестве ключа в многомерной модели. Это упрощает процесс загрузки и помогает виртуализировать информационные витрины.</p>
<p>Несмотря на ключи в таблице, таблица измерения содержит описательные данные, которые описывают <strong>dimension entry (сущность измерения)</strong>. Очень часто таблицы размерностей состоят из множества описательных атрибутов. Их количество может достигать 50 или 100 столбцов. С другой стороны, такие таблицы часто не содержат большого количества строк. Существуют некоторые размерности, такие как размерность <code>Passenger</code>, представленная на рисунке 7.3, которые могут содержать много записей, но большинство измерений довольно малы, содержащие, возможно, не более сотни записей.</p>
<p>Не все числовые атрибуты должны быть мерами в таблице фактов. Например, номер ряда сидений в самолёте не используется ни в каких вычислениях. Он может использоваться как натуральный ключ, но не агрегируется бизнес-пользователем. То же самое относится к возрасту пассажира, если только бизнес не хочет рассчитывать средний возраст пассажиров самолёта. Существуют различные типы мер в таблице фактов многомерной модели данных:</p>
<ul>
<li><strong>Полностью аддитивные меры (Fully additive measures):</strong> полностью аддитивны в том смысле, что такие значения, как суммы и количества, могут быть просуммированы до допустимого общего значения.</li>
<li><strong>Полуаддитивные меры (Semi-additive measures):</strong> могут быть просуммированы по некоторым доступным размерностям, но не по всем.</li>
<li><strong>Неаддитивные меры (Nonadditive measures):</strong> не поддаются сложению.</li>
</ul>
<p>Таким образом, это также зависит от бизнес-потребностей, станет ли атрибут мерой в таблице фактов или описательным атрибутом в одной из её размерностей.</p>
<h2>Запросы к схемам «звезда»</h2>
<p>Конечные пользователи, знакомые со схемами типа «звезда», часто следуют простой схеме при прямом запросе данных из размерной модели:</p>
<ul>
<li><strong>Выбор необходимых фактов:</strong> сначала конечный пользователь решает, какие факты следует выбрать, определяя используемые таблицы фактов.</li>
<li><strong>Выбор необходимых измерений:</strong> добавляя размерности к запросу через соединения (join), конечные пользователи добавляют необходимый контекст.</li>
<li><strong>Ограничение области фактов:</strong> факты фильтруются в соответствии со значениями измерений (либо из таблицы фактов по ключам, либо из присоединённых размерностей).</li>
<li><strong>Агрегация фактов:</strong> исходные факты агрегируются с помощью агрегатных функций, таких как <code>SUM()</code> или <code>COUNT()</code>.</li>
</ul>
<p>Поскольку такой подход настолько распространён, многие производители СУБД оптимизировали свои реляционные движки под подобные запросы, включая Microsoft <strong>за счёт поддержки оптимизации соединений типа «звезда»</strong>.</p>
<p>Следующий оператор может быть использован для запроса к таблице фактов на рисунке 7.2:</p><pre class="urvanov-syntax-highlighter-plain-tag">SELECT
    OriginAirport.Code, AVG(DepartureDelay)
FROM 
    FactFlight
INNER JOIN
    DimAirport OriginAirport ON OriginAirport.AirportKey = FactFlight.OriginAirportKey
WHERE
    OriginAirport.State = 'CA'
GROUP BY
    OriginAirport.Code</pre><p>Этот оператор сначала соединяет таблицу измерений <code>DimAirport</code> с таблицей фактов, используя <code>OriginAirportKey</code>. Обратите внимание, что таблица <code>DimAirport</code> может быть использована дважды:</p>
<ul>
<li>сначала для аэропорта отправления,</li>
<li>затем для аэропорта назначения.</li>
</ul>
<p>Поэтому в операторе для таблицы размерности используется псевдоним <code>OriginAirport</code>.<br />
После того как размерность была присоединена, <strong>состояние аэропорта</strong> используется для фильтрации данных по всем аэропортам Калифорнии. <strong>Штат аэропорта</strong> является описательным атрибутом в таблице измерений. Кроме того, <strong>код аэропорта</strong> используется для группировки данных, чтобы представить пользователю список известных аэропортов Калифорнии со средней задержкой отправления для каждого аэропорта.</p>
<p>Оператор также показывает, как отдельные части SQL-оператора используются в запросах к Dimension модели:</p>
<ul>
<li><strong>Оператор <code>SELECT</code></strong> определяет меры и размерности, которые должны быть представлены конечному пользователю. Также указываются любые формулы, включая агрегатные функции, которые должны быть применены к результату.</li>
<li><strong>Оператор <code>FROM</code></strong> определяет таблицу фактов, к которой выполняется запрос. Во многих случаях это только одна таблица фактов. Однако также возможно выполнение запроса к нескольким таблицам фактов.</li>
<li><strong>Оператор <code>JOIN</code></strong> присоединяет контекст фактов к итоговому результату. Во многих случаях имеется несколько операторов JOIN, каждый из которых соединяет отдельную таблицу измерения.</li>
<li><strong>Оператор <code>WHERE</code></strong> ограничивает область фактов, используемых в результирующем наборе. Во многих случаях доступны данные из дополнительных записей размерности (например, регионы продаж), которые не имеют отношения к выполняемой задаче. Поэтому конечные пользователи обычно ограничивают данные интересующими их записями размерностей.</li>
<li><strong>Оператор <code>GROUP BY</code></strong> определяет, как данные группируются перед агрегацией и представлением конечному пользователю. Агрегация в операторе <strong>SELECT</strong> основана на этом <strong>GROUP BY</strong>. Таким образом, оператор <strong>GROUP BY</strong> используется для изменения гранулярности (grain) результата по сравнению с гранулярностью исходной таблицы фактов.</li>
</ul>
<p><strong>Хотя оператор GROUP BY</strong> может использоваться для повышения уровня гранулярности фактов, невозможно получить результат с более низким уровнем гранулярности. Рассмотрим таблицу фактов, содержащую данные об итогах рейсов: количество пассажиров на борту, аэропорт отправления и назначения, дата рейса и т.д. Если таблица фактов не содержит информации на уровне пассажиров, проанализировать такую информацию невозможно. Поэтому важно правильно выбрать гранулярность таблицы фактов при проектировании <strong>многомерной модели данных</strong>.</p>
<h1>Несколько звёзд (Multiple Stars)</h1>
<p>Оператор в предыдущем разделе использовал только одну таблицу фактов в качестве основы для результата. Однако уже упоминалось, что также возможно использование нескольких таблиц фактов в качестве источника запроса. Это поведение поддерживается <strong>согласованными измерениями (Conformed Dimensions)</strong>, которые используются несколькими звёздами (таблицей фактов с её таблицами измерений) и, следовательно, соединяют эти отдельные звёзды через согласованное измерение.</p>
<h2>Согласованные размерности/измерения (Conformed Dimensions)</h2>
<p><strong>Согласованные измерения</strong> &#8212; это размерности, которые используются несколькими звёздами. Они применяются для сравнения мер из каждой схемы звезда. Повторное использование согласованных размерностей является очень распространённым для «поддержки подлинного анализа бизнес-процессов в разных областях». Это возможно только в том случае, если все схемы звезда, которые должны анализироваться в рамках такого сквозного анализа, используют одну и ту же <strong>таблицу измерений</strong> с точно такими же значениями ключей (первичными ключами). Использование хеш-ключей из модели Data Vault 2.0 упрощает соблюдение этого требования. <strong>Такой анализ называется drill-across</strong> и объединяет информацию из нескольких бизнес-процессов или событий. Только тогда становится возможным анализ данных из различных таблиц фактов с помощью согласованного измерения. На рисунке 7.4 приведён пример.</p>
<p><strong>Рисунок 7.4 Две схемы звезда, соединённые согласованными измерениями (физический дизайн)</strong></p>
<p><a href="https://datatalks.ru/wp-content/uploads/2025/07/image_7_4.jpeg"><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-1795" src="https://datatalks.ru/wp-content/uploads/2025/07/image_7_4.jpeg" alt="" width="1494" height="810" srcset="https://datatalks.ru/wp-content/uploads/2025/07/image_7_4.jpeg 1494w, https://datatalks.ru/wp-content/uploads/2025/07/image_7_4-300x163.jpeg 300w, https://datatalks.ru/wp-content/uploads/2025/07/image_7_4-1024x555.jpeg 1024w, https://datatalks.ru/wp-content/uploads/2025/07/image_7_4-768x416.jpeg 768w, https://datatalks.ru/wp-content/uploads/2025/07/image_7_4-450x244.jpeg 450w, https://datatalks.ru/wp-content/uploads/2025/07/image_7_4-780x423.jpeg 780w" sizes="(max-width: 1494px) 100vw, 1494px" /></a></p>
<p><strong>Исходная картинка:</strong></p>
<p><a href="https://datatalks.ru/wp-content/uploads/2025/07/image_7_4_initial.jpeg"><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-1798" src="https://datatalks.ru/wp-content/uploads/2025/07/image_7_4_initial.jpeg" alt="" width="1186" height="787" srcset="https://datatalks.ru/wp-content/uploads/2025/07/image_7_4_initial.jpeg 1186w, https://datatalks.ru/wp-content/uploads/2025/07/image_7_4_initial-300x199.jpeg 300w, https://datatalks.ru/wp-content/uploads/2025/07/image_7_4_initial-1024x680.jpeg 1024w, https://datatalks.ru/wp-content/uploads/2025/07/image_7_4_initial-768x510.jpeg 768w, https://datatalks.ru/wp-content/uploads/2025/07/image_7_4_initial-450x299.jpeg 450w, https://datatalks.ru/wp-content/uploads/2025/07/image_7_4_initial-780x518.jpeg 780w" sizes="(max-width: 1186px) 100vw, 1186px" /></a></p>
<p>В этом примере имеются две схемы звезда с их таблицами фактов в центре:<br />
<code>FactConnection</code> слева и <code>FactAirportVisit</code> с рисунка 7.1 — справа. Каждая из них имеет ряд подключённых измерений. Обе используют две общие таблицы согласованных измерений &#8212; <code>DimAirport</code> и <code>DimDate</code>, которые показаны в центре схемы. Для поддержки сквозного анализа между <code>FactConnection</code> и <code>FactAirportVisit</code> крайне важно, чтобы обе согласованные размерности имели абсолютно одинаковую структуру и данные.</p>
<p>Чтобы поддерживать такие согласованные размерности, необходимо, чтобы любые изменения в согласованной размерности не нарушали работу одной из размерных звёзд, использующих эту размерность. Это может — и, скорее всего, произойдёт — на последующих спринтах проекта. Всякий раз при изменении структуры или содержания согласованной размерности необходимо пересмотреть влияние на каждую зависимую схему звезда и провести соответствующее тестирование. Поэтому использование согласованных размерностей влечёт за собой влияние изменений, которое может ограничить гибкость команды разработки. Этот избыточный объём сопровождения согласованных размерностей часто приводит к практике, при которой разработчики не изменяют существующие согласованные размерности, чтобы избежать тестирования. Вместо этого они создают новые дополнительные согласованные размерности, чтобы избежать затрат на переинжиниринг, что приводит к несогласованным размерностям. В других случаях они копируют структуру и данные существующих согласованных размерностей в новые схемы звезда и расширяют их новыми функциями, оставляя старую согласованную размерность без изменений (и, следовательно, без необходимости тестирования), снова добавляя несогласованные размерности. Мы называем эту практику <strong>&#171;dimension-itis&#187;</strong>, что приводит к неконтролируемому количеству размерностей, которые вроде бы одинаковые, но… несогласованные.</p>
<p><strong>Обратная практика</strong> — это добавление большего количества атрибутов и данных в существующие согласованные размерности, чтобы избежать создания новых. Этот подход применяется, когда разработчики хотят избежать создания новых согласованных размерностей из-за объёма необходимого тестирования существующих фактов и измерений. Конечный результат такого подхода — так называемая <strong>«деформированная» размерность (“deformed” dimension):</strong> такая размерность не может больше устойчиво изменяться из-за неясных и неконтролируемых изменений в структуре и сложных или запутанных зависимостей, и становится кошмаром с огромными затратами на переинжиниринг при необходимости изменений в будущем. Команды, создающие такие деформированные размерности, как правило, избегают их документирования, что создаёт дополнительные сложности для их преемников.</p>
<p>Мы не рекомендуем отказываться от использования согласованных размерностей. То, что действительно необходимо — это способ быстро создавать и изменять их с низкими затратами на сопровождение. Наша рекомендация — использовать виртуальные информационные витрины.</p>
<h1>Проектирование измерений (Dimension Design)</h1>
<p>Последний раздел этой главы охватывает некоторые дополнительные концепции <strong>многомерного моделирования (Dimension Modeling)</strong>, включая медленно изменяющиеся измерения, иерархии и краткое введение в схему &#171;Снежинка&#187; — более расширенную размерную модель.</p>
<h2>Медленно изменяющиеся измерения (Slowly Changing Dimensions, SCD)</h2>
<p>До этого момента <strong>измерения (dimensions)</strong> рассматривались как сущности, обеспечивающие контекст для фактов. Это верно, но важно понимать, что этот контекст со временем меняется. Например, домашний адрес пассажиров может изменяться из-за переезда, фамилия — из-за брака, а обращение — из-за исправления ошибки. Поскольку связь между схемой звезда и измерением основана на значениях ключей, модель может учитывать изменения в системе-источнике наилучшим образом для удовлетворения требований анализа: изменения могут либо отслеживаться внутри измерения, либо перезаписывать существующие данные в измерении.</p>
<p><strong>Медленно изменяющиеся измерения</strong> используются для обработки изменений в таблицах измерений. Это связано с тем, что темп изменения размерностей относительно медленный, особенно по сравнению с быстро меняющимися таблицами фактов. Поскольку существует несколько способов отслеживания истории в измерениях, Кимбалл ввёл классификацию для таблиц измерений.</p>
<p><strong>Slowly Changing Dimension Type 0 (Медленно изменяющееся измерение Типа 0)</strong> сохраняет исходные значения атрибутов измерения. Если в системе-источнике происходит изменение, значение в таблице измерений не изменяется. Хотя этот тип встречается реже, чем следующие три, он может использоваться для хранения исходного кредитного рейтинга клиента или любого другого первоначального значения.</p>
<p>Изменения в системе-источнике перезаписывают данные в <strong>Slowly Changing Dimension Type 1 (Медленно изменяющемся измерении Типа 1)</strong>. Атрибут измерения всегда отражает наиболее актуальное значение. Следовательно, история не отслеживается. Если на этом атрибуте основана агрегация (например, в предложении <code>GROUP BY</code> оператора), результаты этих агрегаций будут меняться в зависимости от нового значения. В таблице 7.2 приведён пример SCD типа 1.</p>
<p><strong>Таблица 7.2 Медленно изменяющаяся размерность типа 1</strong></p>
<p><a href="https://datatalks.ru/wp-content/uploads/2025/07/table_7_2.png"><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-1781" src="https://datatalks.ru/wp-content/uploads/2025/07/table_7_2.png" alt="" width="1267" height="223" srcset="https://datatalks.ru/wp-content/uploads/2025/07/table_7_2.png 1267w, https://datatalks.ru/wp-content/uploads/2025/07/table_7_2-300x53.png 300w, https://datatalks.ru/wp-content/uploads/2025/07/table_7_2-1024x180.png 1024w, https://datatalks.ru/wp-content/uploads/2025/07/table_7_2-768x135.png 768w, https://datatalks.ru/wp-content/uploads/2025/07/table_7_2-450x79.png 450w, https://datatalks.ru/wp-content/uploads/2025/07/table_7_2-780x137.png 780w" sizes="(max-width: 1267px) 100vw, 1267px" /></a></p>
<p>Таблица размерности, представлена в таблице 7.2, содержит адресную информацию о пассажирах.<br />
Каждый пассажир идентифицируется по ключу, который является первичным ключом и используется таблицей фактов, и по натуральному ключу — номеру паспорта. Все остальные атрибуты в измерении имеют описательный характер и подробно описывают текущий адрес.<br />
Когда пассажир переезжает, текущая запись перезаписывается. Таким образом, история в таблице измерения не сохраняется. Таблица отражает только текущий адрес, а не предыдущие адреса пассажира.</p>
<p>Вместо перезаписи существующих данных, изменения в системе-источнике добавляют новую строку в таблицу <strong>Slowly Changing Dimension Type 2 (Медленно изменяющееся измерение Типа 2)</strong>. Используя такой подход, часто можно корректно отслеживать историю. Поэтому это является преобладающей техникой отслеживания истории в информационных витринах. Пример размерности типа 2 представлен в таблице 7.3.</p>
<p><strong>Таблица 7.3. Медленно изменяющаяся размерность типа 2</strong></p>
<p><a href="https://datatalks.ru/wp-content/uploads/2025/07/table_7_3.png"><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-1783" src="https://datatalks.ru/wp-content/uploads/2025/07/table_7_3.png" alt="" width="1285" height="275" srcset="https://datatalks.ru/wp-content/uploads/2025/07/table_7_3.png 1285w, https://datatalks.ru/wp-content/uploads/2025/07/table_7_3-300x64.png 300w, https://datatalks.ru/wp-content/uploads/2025/07/table_7_3-1024x219.png 1024w, https://datatalks.ru/wp-content/uploads/2025/07/table_7_3-768x164.png 768w, https://datatalks.ru/wp-content/uploads/2025/07/table_7_3-450x96.png 450w, https://datatalks.ru/wp-content/uploads/2025/07/table_7_3-780x167.png 780w" sizes="(max-width: 1285px) 100vw, 1285px" /></a></p>
<p>Таблица (модифицирована из таблицы 7.2 и адаптирована для цели) показывает, как изменения отслеживаются в медленно изменяющейся размерности типа 2: каждая новая версия записи добавляется как дополнительная строка в таблицу размерности.</p>
<p>В этом примере Эми Миллер, с ключом <code>1b3ba82...</code>, вышла замуж за Петера Хайнца, с ключом <code>28ab342...</code>, и переехала к нему в Калифорнию. Поэтому её новая запись с ключом <code>444bbaa...</code> отражает эти изменения. Старая запись остаётся нетронутой, чтобы сохранить историческую информацию. Старые факты продолжают использовать запись с ключом <code>1b3ba82...</code>, но новые факты ссылаются на запись размерности с ключом <code>444bbaa...</code>.</p>
<p>Изменения в <strong>медленно изменяющейся размерности типа 3</strong> не добавляют дополнительных строк, а отслеживают историю в дополнительных столбцах. Для каждого атрибута, подлежащего историзации, добавляется новый столбец для каждого изменения, произошедшего в системе-источнике и подлежащего отображению бизнес-пользователю. Это упрощает анализ изменений со временем. Пример приведён в таблице 7.4.</p>
<p><strong>Таблица 7.4. Медленно изменяющаяся размерность типа 3</strong></p>
<p><a href="https://datatalks.ru/wp-content/uploads/2025/07/table_7_4.png"><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-1784" src="https://datatalks.ru/wp-content/uploads/2025/07/table_7_4.png" alt="" width="1290" height="242" srcset="https://datatalks.ru/wp-content/uploads/2025/07/table_7_4.png 1290w, https://datatalks.ru/wp-content/uploads/2025/07/table_7_4-300x56.png 300w, https://datatalks.ru/wp-content/uploads/2025/07/table_7_4-1024x192.png 1024w, https://datatalks.ru/wp-content/uploads/2025/07/table_7_4-768x144.png 768w, https://datatalks.ru/wp-content/uploads/2025/07/table_7_4-450x84.png 450w, https://datatalks.ru/wp-content/uploads/2025/07/table_7_4-780x146.png 780w" sizes="(max-width: 1290px) 100vw, 1290px" /></a></p>
<p>Этот пример показывает, как бизнес отслеживает предыдущее состояние пассажира с помощью дополнительного столбца. Когда пассажир переезжает, как в случае с Эми Миллер (теперь Эми Хайнц) в записи с ключом <code>1b3ba82...</code>, старый адрес перезаписывается, а атрибуты, которые должны быть исторически отслежены, копируются в дополнительные столбцы. В данном случае столбец <strong>Previous State</strong> обновляется, чтобы отразить предыдущее состояние пассажира.</p>
<p>История не ограничивается только одной записью. Обычно используется ограниченное количество столбцов для хранения нескольких изменений — <strong>в большинстве случаев только текущего и предыдущего значения</strong>. В других случаях ключевые показатели эффективности (KPI) отслеживаются со временем, как в примере в таблице 7.5.</p>
<p><strong>Таблица 7.5. Медленно изменяющаяся размерность типа 3 с несколькими столбцами</strong></p>
<p><a href="https://datatalks.ru/wp-content/uploads/2025/07/table_7_5.png"><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-1785" src="https://datatalks.ru/wp-content/uploads/2025/07/table_7_5.png" alt="" width="1198" height="201" srcset="https://datatalks.ru/wp-content/uploads/2025/07/table_7_5.png 1198w, https://datatalks.ru/wp-content/uploads/2025/07/table_7_5-300x50.png 300w, https://datatalks.ru/wp-content/uploads/2025/07/table_7_5-1024x172.png 1024w, https://datatalks.ru/wp-content/uploads/2025/07/table_7_5-768x129.png 768w, https://datatalks.ru/wp-content/uploads/2025/07/table_7_5-450x76.png 450w, https://datatalks.ru/wp-content/uploads/2025/07/table_7_5-780x131.png 780w" sizes="(max-width: 1198px) 100vw, 1198px" /></a></p>
<p>Таблица 7.5 показывает размерность, которая отслеживает доступные рейсы, их отправные точки и аэропорты назначения. В дополнение к этой основной информации, таблица измерения содержит три значения KPI, которые показывают, как изменялось среднее количество пассажиров за последние три года (включая текущий год).</p>
<p>В дополнение к представленным типам размерностей, в некоторых случаях встречаются и следующие:</p>
<ul>
<li><strong>Slowly changing dimension type 4 (Медленно изменяющаяся размерность типа 4):</strong> этот тип выносит изменчивые атрибуты в отдельную мини-размерность.</li>
<li><strong>Slowly changing dimension type 5 (Медленно изменяющаяся размерность типа 5):</strong> гибрид типов 4 и 1 (4 + 1 = 5). Позволяет получить доступ к текущим атрибутам мини-размерности вместе с другими из основной размерности без связывания через таблицу фактов.</li>
<li><strong>Slowly changing dimension type 6 (Медленно изменяющаяся размерность типа 6):</strong> этот тип добавляет текущие атрибуты к размерности типа 2.</li>
<li><strong>Slowly changing dimension type 7 (Медленно изменяющаяся размерность типа 7):</strong> этот тип обеспечивает ту же функциональность, что и тип 6, но с использованием двух внешних ключей в таблице фактов: один ссылается на размерность типа 2 с отслеживаемыми атрибутами, а другой — на текущую строку.</li>
</ul>
<h2>Иерархии</h2>
<p><strong>Иерархии (Hierarchies)</strong> &#8212; ещё одна важная концепция в размерном моделировании. Они позволяют производить детализацию данных для более глубокого анализа. Рассмотрим следующий пример:<br />
В Excel PivotTable представлена мировая выручка от пассажиров за несколько лет в виде общих значений (см. рисунок 7.5).</p>
<p><strong>Рисунок 7.5 Выручка от пассажиров по годам и регионам</strong></p>
<p><a href="https://datatalks.ru/wp-content/uploads/2025/07/image_7_5.jpeg"><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-1801" src="https://datatalks.ru/wp-content/uploads/2025/07/image_7_5.jpeg" alt="" width="980" height="331" srcset="https://datatalks.ru/wp-content/uploads/2025/07/image_7_5.jpeg 980w, https://datatalks.ru/wp-content/uploads/2025/07/image_7_5-300x101.jpeg 300w, https://datatalks.ru/wp-content/uploads/2025/07/image_7_5-768x259.jpeg 768w, https://datatalks.ru/wp-content/uploads/2025/07/image_7_5-450x152.jpeg 450w, https://datatalks.ru/wp-content/uploads/2025/07/image_7_5-780x263.jpeg 780w" sizes="(max-width: 980px) 100vw, 980px" /></a></p>
<p>Столбцы на рисунке 7.5 показывают финансовые годы (FY) из размерности даты, доступные в сводной таблице. Строки отображают географические регионы из размерности географии. Кроме того, присутствуют общие итоги, показывающие совокупное значение для каждого столбца или строки. Например, выручка от пассажиров за финансовый год 2008 в Соединённых Штатах составила $19,471,989.04.</p>
<p><strong>Географическая иерархия состоит из следующих уровней:</strong></p>
<ul>
<li>Страна</li>
<li>Штат/Провинция</li>
<li>Город</li>
<li>Почтовый индекс</li>
</ul>
<p>Возможно <strong>выполнение детализации (drill-down) до любого уровня</strong>, который доступен в сводной таблице (которая основана на OLAP-кубе), но не глубже. Рисунок 7.6 показывает логическую модель, в которой представлена размерность географии с её иерархией.</p>
<p><strong>Рисунок 7.6 Размерность географии (логическая модель)</strong></p>
<p><a href="https://datatalks.ru/wp-content/uploads/2025/07/image_7_6.jpeg"><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-1802" src="https://datatalks.ru/wp-content/uploads/2025/07/image_7_6.jpeg" alt="" width="220" height="644" srcset="https://datatalks.ru/wp-content/uploads/2025/07/image_7_6.jpeg 220w, https://datatalks.ru/wp-content/uploads/2025/07/image_7_6-102x300.jpeg 102w" sizes="(max-width: 220px) 100vw, 220px" /></a></p>
<p>Обозначения следуют <strong>методологии моделирования ADAPT (Application Design for Analytical Processing Technologies)</strong> для размерных баз данных. Эта методология часто используется в индустрии для моделирования и документирования размерных моделей. Первый элемент изображает саму размерность Geography. Размерность включает одну иерархию, также называемую Geography. Остальные элементы представляют собой отдельные уровни иерархии и должны следовать в указанном порядке. Мы будем использовать методологию моделирования ADAPT на протяжении всей книги.</p>
<p>Аналогично иерархии Geography, иерархия Fiscal Calendar состоит из нескольких уровней:</p>
<ul>
<li>Финансовый год</li>
<li>Финансовое полугодие</li>
<li>Финансовый квартал</li>
<li>Месяц</li>
<li>Дата</li>
</ul>
<p>Эта иерархия очень распространена в системах хранилищ данных и часто используется конечными пользователями. Она использует другую дату начала года, что часто практикуется коммерческими организациями. Например, предприятия в сфере торговли часто начинают финансовый год не с 31 декабря. Это связано с большим числом возвратов после Рождества, совершаемых клиентами, недовольными подарками. Поскольку объём таких возвратов достаточно велик, он оказывает влияние на общую выручку за год. Однако в большинстве случаев возвраты происходят в январе следующего календарного года. Если компания закрывает отчётный год 31 декабря, возвраты будут отнесены к следующему финансовому периоду и исказят финансовые результаты. Поэтому такие компании часто выбирают другой месяц в качестве окончания финансового периода. Один из примеров — Best Buy, розничный продавец электроники в США. Финансовый год этой компании заканчивается 1 февраля. Рисунок 7.7 показывает логическую модель размерности Date.</p>
<p><strong>Рисунок 7.7 Размерность даты (логическая модель)</strong></p>
<p><a href="https://datatalks.ru/wp-content/uploads/2025/07/image_7_7.jpeg"><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-1803" src="https://datatalks.ru/wp-content/uploads/2025/07/image_7_7.jpeg" alt="" width="341" height="620" srcset="https://datatalks.ru/wp-content/uploads/2025/07/image_7_7.jpeg 341w, https://datatalks.ru/wp-content/uploads/2025/07/image_7_7-165x300.jpeg 165w" sizes="(max-width: 341px) 100vw, 341px" /></a></p>
<p>Обратите внимание, что в размерности доступны две иерархии: Calendar и Fiscal Calendar. Обе имеют свои собственные уровни Год, Полугодие и Квартал, но разделяют уровни Месяц и Дата. Обе иерархии используют все атрибуты размерности, но организованы по-разному. В зависимости от потребностей бизнес-аналитика используется та или иная иерархия. Обе являются корректными; ценность каждой иерархии зависит от контекста бизнес-анализа.</p>
<p>Чтобы более подробно проанализировать информацию на рисунке 7.5, можно нажать знак «плюс» рядом с меткой строки и выполнить детализацию по иерархии географии, как показано на рисунке 7.8.</p>
<p><strong>Рисунок 7.8 Выручка от пассажиров в Соединённых Штатах по годам</strong></p>
<p><a href="https://datatalks.ru/wp-content/uploads/2025/07/image_7_8.jpeg"><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-1804" src="https://datatalks.ru/wp-content/uploads/2025/07/image_7_8.jpeg" alt="" width="477" height="754" srcset="https://datatalks.ru/wp-content/uploads/2025/07/image_7_8.jpeg 477w, https://datatalks.ru/wp-content/uploads/2025/07/image_7_8-190x300.jpeg 190w, https://datatalks.ru/wp-content/uploads/2025/07/image_7_8-450x711.jpeg 450w" sizes="(max-width: 477px) 100vw, 477px" /></a></p>
<p>Общая выручка от пассажиров, которая всё ещё отображается в строке, выделенной полужирным шрифтом, разбивается по штатам — следующий географический уровень ниже уровня страны. Для каждого штата показывается выручка от пассажиров по годам. Можно дополнительно разбить эти данные, выполнив детализацию до следующего уровня (рисунок 7.9).</p>
<p><strong>Рисунок 7.9 Выручка от пассажиров в штате Алабама по годам</strong></p>
<p><a href="https://datatalks.ru/wp-content/uploads/2025/07/image_7_9.jpeg"><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-1805" src="https://datatalks.ru/wp-content/uploads/2025/07/image_7_9.jpeg" alt="" width="477" height="799" srcset="https://datatalks.ru/wp-content/uploads/2025/07/image_7_9.jpeg 477w, https://datatalks.ru/wp-content/uploads/2025/07/image_7_9-179x300.jpeg 179w, https://datatalks.ru/wp-content/uploads/2025/07/image_7_9-450x754.jpeg 450w" sizes="(max-width: 477px) 100vw, 477px" /></a></p>
<p>На рисунке 7.9 проводится более глубокий анализ выручки от пассажиров для штата Алабама. Показан каждый город в Алабаме, и выручка от пассажиров для каждого города представлена по годам. Столбец даты представляет собой аналогичную иерархию. Также возможно выполнить детализацию этой иерархии.</p>
<p>На рисунке 7.10 показаны только данные за финансовый год 2007, но более детализировано. Обратите внимание, что отображаются первые три месяца финансового года, который начинается в июле. Для каждого месяца, квартала и полугодия в правой части таблицы показаны итоговые значения. Такой подход позволяет бизнес-аналитикам глубоко понять представленную информацию.</p>
<p><strong>Рисунок 7.10 Выручка от пассажиров в Алабаме по годам, в деталях</strong></p>
<p><a href="https://datatalks.ru/wp-content/uploads/2025/07/image_7_10.jpeg"><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-1806" src="https://datatalks.ru/wp-content/uploads/2025/07/image_7_10.jpeg" alt="" width="980" height="872" srcset="https://datatalks.ru/wp-content/uploads/2025/07/image_7_10.jpeg 980w, https://datatalks.ru/wp-content/uploads/2025/07/image_7_10-300x267.jpeg 300w, https://datatalks.ru/wp-content/uploads/2025/07/image_7_10-768x683.jpeg 768w, https://datatalks.ru/wp-content/uploads/2025/07/image_7_10-450x400.jpeg 450w, https://datatalks.ru/wp-content/uploads/2025/07/image_7_10-780x694.jpeg 780w" sizes="(max-width: 980px) 100vw, 980px" /></a></p>
<p>Иерархия географии реализована физически из таблицы размерности, как показано на рисунке 7.11.</p>
<p><strong>Рисунок 7.11 Размерность географии (физическая модель)</strong></p>
<p><a href="https://datatalks.ru/wp-content/uploads/2025/07/image_7_11.jpeg"><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-1807" src="https://datatalks.ru/wp-content/uploads/2025/07/image_7_11.jpeg" alt="" width="473" height="534" srcset="https://datatalks.ru/wp-content/uploads/2025/07/image_7_11.jpeg 473w, https://datatalks.ru/wp-content/uploads/2025/07/image_7_11-266x300.jpeg 266w, https://datatalks.ru/wp-content/uploads/2025/07/image_7_11-450x508.jpeg 450w" sizes="(max-width: 473px) 100vw, 473px" /></a></p>
<p>Каждый уровень иерархии основан на одном из физических атрибутов таблицы размерности. Связь между атрибутом и уровнем иерархии задаётся в Microsoft SQL Server Analysis Services. Аналогичные иерархии будут реализованы в этой главе при построении OLAP-куба и добавлении размерности даты как иерархии.</p>
<h2>Дизайн &#171;Снежинка&#187; (Snowflake Design)</h2>
<p>В этой главе была представлена схема «звезда», основанная на таблице фактов в центре и сопровождающих её таблицах размерностей, которые предоставляют контекст для фактов. Эти таблицы измерений напрямую соединяются с таблицей фактов. Косвенное соединение таблиц измерений &#8212; то есть, когда одна таблица измерения ссылается на другую таблицу измерения — невозможно в схеме звезда. Это справедливо даже в случае наличия связи между атрибутами измерений.</p>
<p>Рассмотрим пример корпоративных групп в авиационной индустрии и отдельных авиаперевозчиков. Каждая авиакомпания входит в состав более крупной группы, которая владеет этим перевозчиком. Например, United Continental Holdings, Inc. владеет как United Airlines, так и Continental Airlines, а также другими, более мелкими перевозчиками.</p>
<p>Если схема звезда должна отразить эту связь, обе размерности — <code>DimGroup</code> и <code>DimCarrier</code> — должны быть напрямую связаны с таблицей фактов, как показано на рисунке 7.12.</p>
<p><strong>Рисунок 7.12 Схема звезда с таблицей фактов в центре и только напрямую связанными размерностями (физическая модель)</strong></p>
<p><a href="https://datatalks.ru/wp-content/uploads/2025/07/image_7_12.jpeg"><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-1808" src="https://datatalks.ru/wp-content/uploads/2025/07/image_7_12.jpeg" alt="" width="691" height="806" srcset="https://datatalks.ru/wp-content/uploads/2025/07/image_7_12.jpeg 691w, https://datatalks.ru/wp-content/uploads/2025/07/image_7_12-257x300.jpeg 257w, https://datatalks.ru/wp-content/uploads/2025/07/image_7_12-450x525.jpeg 450w" sizes="(max-width: 691px) 100vw, 691px" /></a></p>
<p>Этот пример повторяет представленный на рисунке 7.4. Однако он показывает только одну схему звезда. Обратите внимание на две размерности <code>DimGroup</code> и <code>DimCarrier</code>, которые независимо связаны с таблицей фактов. Тем не менее, между этими двумя размерностями существует неявная связь. Эта связь реализована в ETL-задании, которое загружает таблицу. ETL-задание гарантирует, что в таблицу фактов загружаются только допустимые комбинации <code>CarrierKey</code> и <code>GroupKey</code>. Модель не реализует никаких правил, которые препятствовали бы загрузке недопустимых комбинаций. С другой стороны, эта модель проста в использовании для бизнес-пользователей, потому что они могут напрямую соединять всю необходимую контекстную информацию. Именно поэтому схема звезда допускает только напрямую связанные таблицы измерений.</p>
<p><strong>Например, чтобы получить среднюю задержку группы, можно использовать следующий оператор:</strong></p><pre class="urvanov-syntax-highlighter-plain-tag">SELECT
    DimGroup.Name, AVG(DepDelay)
FROM 
    FactConnection
INNER JOIN
    DimGroup ON DimGroup.GroupKey = FactConnection.GroupKey
GROUP BY
    DimGroup.Name</pre><p>Как видно из запроса, не требуется больших усилий, чтобы добавить группу в результирующий набор. Соединение осуществляется напрямую с использованием поля <code>GroupKey</code> в таблице фактов.</p>
<p><strong>Схема «снежинка»</strong>, с другой стороны, допускает косвенные таблицы измерений. Это полезно, если необходимо явно смоделировать отношения между атрибутами измерений. Если бы модель на рисунке 7.12 была реализована как схема «снежинка», она выглядела бы примерно как на рисунке 7.13.</p>
<p><strong>Рисунок 7.13 Схема снежинка с таблицей фактов в центре и косвенно связанными измерениями (физическая модель)</strong></p>
<p><a href="https://datatalks.ru/wp-content/uploads/2025/07/image_7_13.jpeg"><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-1809" src="https://datatalks.ru/wp-content/uploads/2025/07/image_7_13.jpeg" alt="" width="691" height="809" srcset="https://datatalks.ru/wp-content/uploads/2025/07/image_7_13.jpeg 691w, https://datatalks.ru/wp-content/uploads/2025/07/image_7_13-256x300.jpeg 256w, https://datatalks.ru/wp-content/uploads/2025/07/image_7_13-450x527.jpeg 450w" sizes="(max-width: 691px) 100vw, 691px" /></a></p>
<p>Как видно из диаграммы, <strong>термин «снежинка»</strong> происходит от внешнего вида модели. Таблицы измерений отходят от центральной таблицы фактов, подобно лучам снежинки. Вместо того чтобы напрямую ссылаться на <code>DimGroup</code> из <code>FactConnection</code>, группа ссылается косвенно через <code>DimCarrier</code>. <code>GroupKey</code>, который идентифицирует группу в таблице фактов, перемещён в <code>DimCarrier</code>. Чтобы вернуть среднюю задержку группы, как в предыдущем запросе, необходимо сначала соединить <code>DimCarrier</code>, а затем <code>DimGroup</code>.</p>
<p>Это не представляет проблемы, если вы умеете писать SQL-запросы и не испытываете трудностей при косвенном соединении таблиц, как в этом случае. Для опытного разработчика баз данных такой запрос не представляет никакой угрозы. Однако если бизнес-аналитики с меньшими знаниями и опытом работы с SQL-запросами должны работать со схемами снежинка, они могут почувствовать себя перегруженными и не справиться с базой данных.</p>
<p>Несмотря на эту проблему, <strong>схемы снежинка</strong> на самом деле используются довольно часто.</p>
<p>Сообщение <a href="https://datatalks.ru/chapter-7-data-vault-2-0-dimensional-modeling/">Перевод 7 Главы &#8212; Dimensional Modeling (Data Vault 2.0)</a> появились сначала на <a href="https://datatalks.ru">DataTalks.RU. Data Engineering / DWH / Data Pipeline</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://datatalks.ru/chapter-7-data-vault-2-0-dimensional-modeling/feed/</wfw:commentRss>
			<slash:comments>6</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>
