Поделиться через


Моделирование данных в Azure Cosmos DB для NoSQL

Хотя базы данных без схемы, такие как Azure Cosmos DB, позволяют легко хранить и запрашивать неструктурированные и частично структурированные данные, думайте о модели данных для оптимизации производительности, масштабируемости и затрат.

Как хранятся данные? Как приложение получает и запрашивает данные? Работает ли приложение с большим объемом чтения или записи?

Прочитав эту статью, вы можете ответить на следующие вопросы:

  • Что такое моделирование данных и почему оно так важно?
  • Как моделировать данные в Azure Cosmos DB отличается от реляционной базы данных?
  • Как выразить связи данных в нереляционной базе данных?
  • Когда следует встроить данные, а когда — ссылаться на них?

Числа в JSON

Azure Cosmos DB сохраняет документы в ФОРМАТЕ JSON, поэтому важно определить, следует ли преобразовывать числа в строки, прежде чем хранить их в ФОРМАТЕ JSON. Преобразуйте все числа в число, если они могут превышать границы String цифр двойной точности, как определено Институтом инженеров электротехники (IEEE) 754 binary64. Спецификация JSON объясняет, почему использование чисел за пределами этой границы является плохой практикой из-за проблем взаимодействия. Эти проблемы особенно важны для столбца ключа секции, так как это неизменяемо и требует миграции данных позже.

Внедрение данных

При моделировать данные в Azure Cosmos DB следует рассматривать сущности как автономные элементы , представленные как документы JSON.

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

Снимок экрана: модель реляционной базы данных.

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

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

SELECT p.FirstName, p.LastName, a.City, cd.Detail
FROM Person p
JOIN ContactDetail cd ON cd.PersonId = p.Id
JOIN ContactDetailType cdt ON cdt.Id = cd.TypeId
JOIN Address a ON a.PersonId = p.Id

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

А сейчас давайте рассмотрим, как смоделировать аналогичные данные в виде автономной сущности в Azure Cosmos DB.

{
    "id": "1",
    "firstName": "Thomas",
    "lastName": "Andersen",
    "addresses": [
        {
            "line1": "100 Some Street",
            "line2": "Unit 1",
            "city": "Seattle",
            "state": "WA",
            "zip": 98012
        }
    ],
    "contactDetails": [
        {"email": "thomas@andersen.com"},
        {"phone": "+1 555 555-5555", "extension": 5555}
    ]
}

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

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

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

Когда внедрять

В общем случае модели внедренных данных следует использовать в следующих ситуациях:

  • между сущностями существуют содержащиеся связи;
  • между сущностями существуют отношения один к нескольким.
  • Данные редко изменяются.
  • Данные не растут без привязки.
  • Данные часто запрашиваются вместе.

Примечание.

Обычно модели денормализованных данных обеспечивают повышенную производительность при чтении .

Когда не следует внедрять

Хотя правило большого пальца в Azure Cosmos DB заключается в денормализации всего и внедрении всех данных в один элемент, этот подход может привести к ситуациям, чтобы избежать.

Рассмотрим этот фрагмент кода JSON.

{
    "id": "1",
    "name": "What's new in the coolest Cloud",
    "summary": "A blog post by someone real famous",
    "comments": [
        {"id": 1, "author": "anon", "comment": "something useful, I'm sure"},
        {"id": 2, "author": "bob", "comment": "wisdom from the interwebs"},
        …
        {"id": 100001, "author": "jane", "comment": "and on we go ..."},
        …
        {"id": 1000000001, "author": "angry", "comment": "blah angry blah angry"},
        …
        {"id": ∞ + 1, "author": "bored", "comment": "oh man, will this ever end?"},
    ]
}

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

По мере увеличения размера элемента, передачи, чтения и обновления данных в масштабе становится более сложной задачей.

В этом случае лучше рассмотреть следующую модель данных.

Post item:
{
    "id": "1",
    "name": "What's new in the coolest Cloud",
    "summary": "A blog post by someone real famous",
    "recentComments": [
        {"id": 1, "author": "anon", "comment": "something useful, I'm sure"},
        {"id": 2, "author": "bob", "comment": "wisdom from the interwebs"},
        {"id": 3, "author": "jane", "comment": "....."}
    ]
}

Comment items:
[
    {"id": 4, "postId": "1", "author": "anon", "comment": "more goodness"},
    {"id": 5, "postId": "1", "author": "bob", "comment": "tails from the field"},
    ...
    {"id": 99, "postId": "1", "author": "angry", "comment": "blah angry blah angry"},
    {"id": 100, "postId": "2", "author": "anon", "comment": "yet more"},
    ...
    {"id": 199, "postId": "2", "author": "bored", "comment": "will this ever end?"}   
]

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

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

Рассмотрим этот фрагмент кода JSON.

{
    "id": "1",
    "firstName": "Thomas",
    "lastName": "Andersen",
    "holdings": [
        {
            "numberHeld": 100,
            "stock": { "symbol": "zbzb", "open": 1, "high": 2, "low": 0.5 }
        },
        {
            "numberHeld": 50,
            "stock": { "symbol": "xcxc", "open": 89, "high": 93.24, "low": 88.87 }
        }
    ]
}

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

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

Эталонные данные

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

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

В ФОРМАТЕ JSON мы используем пример портфеля акций из более ранних версий, но на этот раз мы ссылаемся на акции в портфеле вместо внедрения. Таким образом, когда акции часто изменяются в течение дня единственный элемент, который необходимо обновить, является одним документом акций.

Person document:
{
    "id": "1",
    "firstName": "Thomas",
    "lastName": "Andersen",
    "holdings": [
        { "numberHeld":  100, "stockId": 1},
        { "numberHeld":  50, "stockId": 2}
    ]
}

Stock documents:
{
    "id": "1",
    "symbol": "zbzb",
    "open": 1,
    "high": 2,
    "low": 0.5,
    "vol": 11970000,
    "mkt-cap": 42000000,
    "pe": 5.89
},
{
    "id": "2",
    "symbol": "xcxc",
    "open": 89,
    "high": 93.24,
    "low": 88.87,
    "vol": 2970200,
    "mkt-cap": 1005000,
    "pe": 75.82
}

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

Примечание.

Модели нормализованных данных могут потребовать больше круговых путей к серверу.

Что насчет внешних ключей?

Поскольку нет понятия ограничения, например внешнего ключа, база данных не проверяет связи между документами; эти ссылки фактически являются "слабыми". Если вы хотите убедиться, что данные, на которые ссылается элемент, фактически существуют, необходимо выполнить этот шаг в приложении или с помощью триггеров на стороне сервера или хранимых процедур в Azure Cosmos DB.

Когда следует использовать ссылки

В общем случае модели нормализованных данных следует использовать в следующих ситуациях:

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

Примечание.

Обычно нормализация обеспечивает повышенную производительность при записи .

Куда поставить отношения?

Рост связи помогает определить, в каком элементе хранить ссылку.

Если мы рассмотрим JSON, который моделирует издателей и книги.

Publisher document:
{
    "id": "mspress",
    "name": "Microsoft Press",
    "books": [ 1, 2, 3, ..., 100, ..., 1000]
}

Book documents:
{"id": "1", "name": "Azure Cosmos DB 101" }
{"id": "2", "name": "Azure Cosmos DB for RDBMS Users" }
{"id": "3", "name": "Taking over the world one JSON doc at a time" }
...
{"id": "100", "name": "Learn about Azure Cosmos DB" }
...
{"id": "1000", "name": "Deep Dive into Azure Cosmos DB" }

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

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

Publisher document:
{
    "id": "mspress",
    "name": "Microsoft Press"
}

Book documents:
{"id": "1","name": "Azure Cosmos DB 101", "pub-id": "mspress"}
{"id": "2","name": "Azure Cosmos DB for RDBMS Users", "pub-id": "mspress"}
{"id": "3","name": "Taking over the world one JSON doc at a time", "pub-id": "mspress"}
...
{"id": "100","name": "Learn about Azure Cosmos DB", "pub-id": "mspress"}
...
{"id": "1000","name": "Deep Dive into Azure Cosmos DB", "pub-id": "mspress"}

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

Как я могу моделировать отношения "многие ко многим"?

В реляционной базе данных отношения "многие ко многим" часто моделиируются с таблицами соединения. Эти связи просто объединяют записи из других таблиц вместе.

Снимок экрана: присоединение таблиц.

У вас может возникнуть желание реплицировать это с помощью документов и создать модель данных, аналогичную приведенной ниже.

Author documents:
{"id": "a1", "name": "Thomas Andersen" }
{"id": "a2", "name": "William Wakefield" }

Book documents:
{"id": "b1", "name": "Azure Cosmos DB 101" }
{"id": "b2", "name": "Azure Cosmos DB for RDBMS Users" }
{"id": "b3", "name": "Taking over the world one JSON doc at a time" }
{"id": "b4", "name": "Learn about Azure Cosmos DB" }
{"id": "b5", "name": "Deep Dive into Azure Cosmos DB" }

Joining documents:
{"authorId": "a1", "bookId": "b1" }
{"authorId": "a2", "bookId": "b1" }
{"authorId": "a1", "bookId": "b2" }
{"authorId": "a1", "bookId": "b3" }

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

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

Author documents:
{"id": "a1", "name": "Thomas Andersen", "books": ["b1", "b2", "b3"]}
{"id": "a2", "name": "William Wakefield", "books": ["b1", "b4"]}

Book documents:
{"id": "b1", "name": "Azure Cosmos DB 101", "authors": ["a1", "a2"]}
{"id": "b2", "name": "Azure Cosmos DB for RDBMS Users", "authors": ["a1"]}
{"id": "b3", "name": "Learn about Azure Cosmos DB", "authors": ["a1"]}
{"id": "b4", "name": "Deep Dive into Azure Cosmos DB", "authors": ["a2"]}

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

Гибридные модели данных

Мы изучаем внедрение (или денормализацию) и ссылки (или нормализацию) данных. Каждый подход предлагает преимущества и включает компромиссы.

Это не всегда должно быть либо- или. Не стесняйтесь смешивать вещи немного.

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

Давайте рассмотрим следующий код JSON.

Author documents:
{
    "id": "a1",
    "firstName": "Thomas",
    "lastName": "Andersen",
    "countOfBooks": 3,
    "books": ["b1", "b2", "b3"],
    "images": [
        {"thumbnail": "https://....png"}
        {"profile": "https://....png"}
        {"large": "https://....png"}
    ]
},
{
    "id": "a2",
    "firstName": "William",
    "lastName": "Wakefield",
    "countOfBooks": 1,
    "books": ["b1"],
    "images": [
        {"thumbnail": "https://....png"}
    ]
}

Book documents:
{
    "id": "b1",
    "name": "Azure Cosmos DB 101",
    "authors": [
        {"id": "a1", "name": "Thomas Andersen", "thumbnailUrl": "https://....png"},
        {"id": "a2", "name": "William Wakefield", "thumbnailUrl": "https://....png"}
    ]
},
{
    "id": "b2",
    "name": "Azure Cosmos DB for RDBMS Users",
    "authors": [
        {"id": "a1", "name": "Thomas Andersen", "thumbnailUrl": "https://....png"},
    ]
}

Здесь (в основном) следует внедренной модели, где данные из других сущностей внедрены в документ верхнего уровня, но на другие данные ссылаются.

Если взглянуть на документ книги, можно заметить несколько интересных полей в массиве авторов. Существует поле id, которое используется для обратной ссылки на документ автора, что является стандартным решением в модели нормализации, однако также присутствуют поля name и thumbnailUrl. Мы могли использовать только id те сведения, которые требуется приложению, из соответствующего элемента автора с помощью ссылки. Однако, так как приложение отображает имя автора и эскиз рисунка с каждой книгой, денормализация некоторых данных от автора уменьшает количество обходов сервера на книгу в списке.

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

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

Возможность создания модели с предварительно вычисляемых полей возможна, так как Azure Cosmos DB поддерживает многодокументные транзакции. Многие магазины NoSQL не могут выполнять транзакции между документами, поэтому выступают за принятие решений по проектированию, например "всегда внедрять все" из-за этого ограничения. В Azure Cosmos DB вы можете использовать триггеры на стороне сервера или хранимые процедуры, которые вставляют книги и обновляют авторов в рамках транзакции ACID. Теперь вам не нужно внедрять все в один элемент, чтобы убедиться, что данные остаются согласованными.

Различие между различными типами элементов

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

Book documents:
{
    "id": "b1",
    "name": "Azure Cosmos DB 101",
    "bookId": "b1",
    "type": "book"
}

Review documents:
{
    "id": "r1",
    "content": "This book is awesome",
    "bookId": "b1",
    "type": "review"
}
{
    "id": "r2",
    "content": "Best book ever!",
    "bookId": "b1",
    "type": "review"
}

Azure Synapse Link для Azure Cosmos DB — это облачная гибридная транзакционно-аналитическая возможность обработки (HTAP), которая позволяет вам выполнять аналитику операционных данных в Azure Cosmos DB почти в реальном времени. Azure Synapse Link создает простую интеграцию между Azure Cosmos DB и Azure Synapse Analytics.

Эта интеграция выполняется через аналитическое хранилище Azure Cosmos DB, столбцовое представление транзакционных данных, которое позволяет масштабировать аналитику без каких-либо последствий для рабочих нагрузок транзакций. Аналитическое хранилище позволяет выполнять быстрые и доступные запросы для больших наборов данных. Вам не нужно копировать данные или беспокоиться о замедлении работы основной базы данных. При включении аналитического хранилища для контейнера все изменения, внесенные в данные, копируются в аналитическое хранилище почти сразу. Вам не нужно настраивать веб-канал изменений или запускать задания извлечения, преобразования и загрузки (ETL). Система сохраняет синхронизацию обоих хранилищ.

С помощью Azure Synapse Link теперь можно непосредственно подключаться к контейнерам Azure Cosmos DB из Azure Synapse Analytics и обращаться к аналитическому хранилищу, не тратя при этом единицы запросов (ЕЗ). Сейчас Azure Synapse Analytics поддерживает Azure Synapse Link с Synapse Apache Spark и бессерверные пулы SQL. Если вы используете глобально распределенную учетную запись Azure Cosmos DB, после включения аналитического хранилища для контейнера он будет доступен во всех регионах для этой учетной записи.

Автоматическое определение схемы аналитического хранилища

Хранилище транзакций Azure Cosmos DB — это частично структурированные данные, а аналитическое хранилище использует столбец и структурированный формат. Это преобразование выполняется для клиентов автоматически с использованием правил вывода схемы для аналитического хранилища. В процессе преобразования есть ограничения: максимальное количество уровней вложенности, максимальное количество свойств, неподдерживаемые типы данных и другие.

Примечание.

В контексте аналитического хранилища мы рассматриваем следующие структуры как свойство:

  • Пары "элементы" и "строковое значение", разделенные символом " :"
  • Объекты JSON, разделенные { и }
  • Массивы JSON, разделенные и []

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

нормализация

Нормализация становится менее актуальной, так как Azure Synapse Link позволяет присоединять контейнеры с помощью T-SQL или Spark SQL. Ожидаемые преимущества нормализации:

  • меньший объем данных как в транзакционном, так и в аналитическом хранилище;
  • меньший масштаб транзакций;
  • меньше свойств в каждом документе;
  • структуры данных с меньшим количеством уровней вложенности.

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

Еще одним важным фактором нормализации является то, что бессерверные пулы SQL в Azure Synapse поддерживают результирующие наборы с количеством до 1000 столбцов, и отображение вложенных столбцов также входит в это ограничение. Другими словами, как аналитическое хранилище, так и бессерверные пулы Synapse SQL имеют ограничение в 1000 свойств.

Но как поступить, если денормализация — это важный способ моделирования данных для Azure Cosmos DB? Ответ заключается в том, что вы должны найти правильный баланс для транзакционных и аналитических рабочих нагрузок.

Ключ раздела

Ключ секции Azure Cosmos DB (PK) не используется в аналитическом хранилище. Теперь вы можете использовать настраиваемое секционирование аналитического хранилища для копий аналитического хранилища с любым ключом секции, который вам нужен. Благодаря такой изоляции можно выбрать ключ секции для ваших транзакционных данных, уделяя при этом особое внимание приему данных и операциям точечного чтения, а запросы между секциями можно выполнять с помощью Azure Synapse Link. Рассмотрим пример.

В гипотетическом глобальном сценарии device id Интернета вещей используется хороший ключ секции, так как все устройства создают аналогичный объем данных, что предотвращает проблемы с горячими секциями. Но если вы хотите проанализировать данные нескольких устройств, таких как "все данные из вчерашнего дня" или "итоговые данные по городу", могут возникнуть проблемы, так как эти запросы являются межсекционными запросами. Эти запросы могут навредить вашей производительности транзакций, так как они используют часть вашей пропускной способности в единицах запросов для выполнения. Но с помощью Azure Synapse Link можно выполнять эти аналитические запросы без затрат на единицы запросов. Формат столбца аналитического хранилища оптимизирован для аналитических запросов, а Azure Synapse Link поддерживает высокую производительность с помощью среды выполнения Azure Synapse Analytics.

Типы данных и имена свойств

В статье о правилах автоматического вывода схемы перечислены поддерживаемые типы данных. Хотя среды выполнения Azure Synapse могут обрабатывать поддерживаемые типы данных по-разному, неподдерживаемые типы данных блокируют представление в аналитическом хранилище. Один из примеров: при использовании строк DateTime, которые соответствуют стандарту ISO 8601 UTC, пулы Spark в Azure Synapse представляют эти столбцы, как string и бессерверные пулы SQL в Azure Synapse представляют эти столбцы как varchar(8000).

Еще одна проблема заключается в том, что Azure Synapse Spark не принимает все символы. Хотя пробелы принимаются, такие символы, как двоеточие, гравис и запятая, не принимаются. Предположим, что у элемента есть свойство с именем "Имя, фамилия". Это свойство представлено в аналитическом хранилище, а бессерверный пул Synapse SQL может считывать его без проблем. Но поскольку оно хранится в аналитическом хранилище, Azure Synapse Spark не может прочитать никаких данных из аналитического хранилища, включая все остальные свойства. В итоге вы не сможете использовать Azure Synapse Spark, если у вас есть свойство с неподдерживаемыми символами в его названии.

Преобразование данных в плоскую структуру

Каждое свойство на верхнем уровне данных Azure Cosmos DB становится столбцом в аналитическом хранилище. Свойства внутри вложенных объектов или массивов хранятся в виде JSON в аналитическом хранилище, сохраняя их структуру. Вложенные структуры требуют дополнительной обработки из среды выполнения Azure Synapse для выравнивания данных в структурированном формате, что может быть проблемой в сценариях больших данных.

Элемент содержит только два столбца в аналитическом хранилище и idcontactDetails. Все остальные данные email, а также phoneтребуют дополнительной обработки с помощью функций SQL для чтения по отдельности.


{
    "id": "1",
    "contactDetails": [
        {"email": "thomas@andersen.com"},
        {"phone": "+1 555 555-5555"}
    ]
}

Элемент содержит три столбца в аналитическом хранилище, idemailа phoneтакже . Все данные доступны напрямую в виде столбцов.


{
    "id": "1",
    "email": "thomas@andersen.com",
    "phone": "+1 555 555-5555"
}

Распределение данных по уровням

Azure Synapse Link позволяет снизить затраты с учетом следующего:

  • Меньше запросов в транзакционной базе данных.
  • Ключ раздела, оптимизированный для загрузки данных и операций точечного чтения, что уменьшает след данных, сокращает частоту сценариев с "горячими" разделами и случаев разделения разделов.
  • Разделение данных на уровни, так как аналитический срок жизни (attl) не зависит от транзакционного срока жизни (tttl). Транзакционные данные можно хранить в транзакционном хранилище в течение нескольких дней, недель, месяцев, а в аналитическом хранилище — годами или вечно. Столбцовый формат аналитического хранилища обеспечивает естественное сжатие данных со степенью сжатия от 50 % до 90 %. А его стоимость за ГБ составляет около 10 % от фактической стоимости транзакционного хранилища. Дополнительные сведения о текущих ограничениях резервного копирования см. в статье Общие сведения об аналитическом хранилище.
  • Нет заданий ETL, выполняемых в вашей среде, то есть вам не нужно выделять единицы запросов для них.

Контролируемая избыточность

Этот метод является отличной альтернативой для ситуаций, когда модель данных уже существует и не может быть изменена. Текущая модель данных не работает хорошо с аналитическим хранилищем. Это преимущество существует, так как аналитическое хранилище содержит правила, ограничивающие количество уровней, которые можно вложить в данные и сколько свойств можно использовать в каждом документе. Если данные слишком сложны или имеют слишком много полей, некоторые важные сведения могут не включаться в аналитическое хранилище. В этом случае можно использовать канал изменений Azure Cosmos DB для репликации данных в другой контейнер, применяя необходимые преобразования для понятной модели данных Azure Synapse Link. Рассмотрим пример.

Сценарий

Контейнер CustomersOrdersAndItems используется для хранения локальных заказов, включая сведения о клиентах и элементах: адрес выставления счетов, адрес доставки, метод доставки, состояние доставки, цены на элементы и т. д. Представлены только первые 1000 свойств, а ключевые сведения не включены в аналитическое хранилище, блокируя использование Azure Synapse Link. Контейнер содержит петабайты записей, которые невозможно изменить приложение и перемоделировать данные.

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

Что можно сделать?

Решение с использованием канала изменений

  • Инженерная команда решила использовать канал изменений для заполнения трех новых контейнеров: Customers, Orders и Items. При использовании канала изменений они нормализации и выравнивания данных. Из модели данных удаляются ненужные сведения, и каждый контейнер имеет почти 100 свойств, что позволяет избежать потери данных из-за ограничений автоматического вывода схемы.
  • Эти новые контейнеры включают аналитическое хранилище, а отдел аналитики использует Synapse Analytics для чтения данных. Это снижает использование единиц запросов, так как аналитические запросы выполняются в Synapse Apache Spark и бессерверных пулах SQL.
  • Контейнер CustomersOrdersAndItems теперь имеет время ожидания (TTL) для хранения данных только в течение шести месяцев, что позволяет сократить использование единиц запросов, так как в Azure Cosmos DB не менее одного единицы запроса на ГБ. Меньше данных, меньше единиц запросов.

Общие выводы

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

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