Статьи

Три вещи, которые нужно знать о моделировании базы данных документов: Часть 1

Первоначально Написано Мэтью Ревеллом

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

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

Это не сложнее, просто вы оптимизируете под разные вещи.

Итак, каковы основы, чтобы получить это правильно?

Ну, есть три принципа, которые могут помочь вам в вашем мышлении:

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

Сегодня давайте рассмотрим первый из них подробно.

Вопросы, а не ответы

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

Давайте рассмотрим простой пример: систему управления запасами, которая позволяет нам отслеживать марку Couchbase. 

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

Скорее всего, это дало бы нам следующие реляционные таблицы:

  • товары
  • клиенты
  • заказы
  • Информация для заказа

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

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

Компромиссы, всегда есть компромиссы

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

Так в чем проблема?

Ну, есть пара компромиссов:

  • SQL-запросы стоят дорого: для каждого объединения есть поиск диска, есть загрузка ЦП, есть пользователь, ожидающий отображения своей страницы.
  • Реляционные базы данных трудно масштабировать по кластеру.

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

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

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

Не заставляйте людей ждать ответов

Первое, что мы делаем при моделировании для базы данных документов, это спрашиваем: «Какие вопросы я хочу задать своим данным?»

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

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

Что это означает на практике?

Давайте вернемся к нашему примеру управления добычей. Один из наших вопросов будет:

Что мне нужно сделать, чтобы выполнить определенный заказ?

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

С Couchbase это будет выглядеть примерно так:

  1. Пользователь выбирает свои товары и делает заказ.
  2. Наша система записывает заказ в базу данных как единый документ.
  3. Когда нам нужно вытащить детали заказа, это одно чтение, чтобы захватить лот.

Результирующий документ заказа может выглядеть так:

{
    "orderID": 200,
    "customer":
    {
      "name": "Matthew Revell",
      "address": "11-21 Paul Street",
      "city": "London"
    },
    "products":
      [
        {  
           "itemCode": "RedTShirt",
           "itemName": "Red Couchbase t-shirt",
           "quantityOrdered": 3
        },
        {
          "itemCode": "USB",
          "itemName": "Black 8GB USB stick with red Couchbase logo",
          "quantityOrder": 51
        }
      ],
    "status": "paid"
  }

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

Мы рассмотрим компромиссы, связанные с встраиванием данных по сравнению со ссылками на данные, в следующем посте.

Производство сложнее

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

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

Важно то, что нам не нужно генерировать все это, пока человек ждет ответа. 

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

Таким образом, когда человек просматривает что-то в нашей системе, данные уже там ожидают. 

В итоге: предварительно рассчитать ваши ответы

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

Мы заранее знаем, какие вопросы мы хотим задать, и поэтому мы можем удовлетворить эти вопросы так, как мы пишем наши данные.

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

Вычисляя наши различные ответы во время записи, мы:

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

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