Краткий рассказ о дизайне архитектуры MongoDB

задняя часть база данных MongoDB дизайн

Дизайн схемы MongoDB

Ссылка на ссылку:изучите MongoDB трудным путем.com/schema/getting on…

Обзор

Mongodb — это база данных документов. Поскольку это не реляционная база данных, она не обязана соответствовать трем парадигмам, и в ней нет ключевого слова Join для поддержки соединений таблиц. Поэтому структура таблицы Mongodb сильно отличается от Oracle и MySQL. Ниже приведены примеры нескольких различных структур оформления таблиц:

Модель отношений 1 к 1

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

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

Тогда вернемся к Mongodb, в этой нереляционной NoSQL БД нет стандартного внешнего ключа (хотя мы и можем вручную устанавливать соединения, ассоциация полей между такими таблицами может существовать только на программном уровне, а сама БД не существует). Концепции ограничений внешнего ключа не существует), как мы можем создавать таблицы и иметь дело со связями между таблицами?

  1. установить соединение

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

     用户信息的文档设计    
     {
       _id: 1,
       name: "Peter Wilkinson",
       age: 27
     }
    
     保留外键的地址信息的文档设计
     {
       user_id: 1,
       street: "100 some road",
       city: "Nevermore"
     }
  1. встроенный документ

    Непосредственно храните документ с информацией об адресе как поле документа с информацией о пользователе.

     {
        name: "Peter Wilkinson",
       age: 27,
       address: {
         street: "100 some road",
         city: "Nevermore"
       }
     }

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

     官方文档推荐1对1的数据模型尽量使用内嵌的方式,这样子会提高读操作的效率,更快地获取文档信息

Модель отношений 1 ко многим

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

Соответствующая модель таблицы MongoDB выглядит следующим образом.

博客信息的文档设计
{
  title: "An awesome blog",
  url: "http://awesomeblog.com",
  text: "This is an awesome blog we have just started"
}

评论信息的文档设计
{
  name: "Peter Critic",
  created_on: ISODate("2014-01-01T10:01:22Z"),
  comment: "Awesome blog post"
}
{
  name: "John Page",
  created_on: ISODate("2014-01-01T11:01:22Z"),
  comment: "Not so awesome blog"
}

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

Однако, поскольку в Mongodb нет ключевого слова Join, мы можем нарисовать следующие три решения в соответствии с характеристиками Mongodb:

  1. в линию

     内嵌了评论信息的博客文档设计
     {
       title: "An awesome blog",
       url: "http://awesomeblog.com",
       text: "This is an awesome blog we have just started",
       comments: [{
         name: "Peter Critic",
         created_on: ISODate("2014-01-01T10:01:22Z"),
         comment: "Awesome blog post"
       }, {
         name: "John Page",
         created_on: ISODate("2014-01-01T11:01:22Z"),
         comment: "Not so awesome blog"
       }]
     }

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

    Однако у этой конструкции таблицы есть по крайней мере три потенциальных проблемы, о которых следует знать:

    1. Массив комментариев под блогом может постепенно увеличиваться, даже превышая максимальный размер документа: 16 МБ.
    2. Вторая проблема связана с производительностью записи. Поскольку комментарии постоянно добавляются в документы блога, когда новый документ блога вставляется в коллекцию, MongoDB будет сложно найти исходное местоположение документа блога. Кроме того, база данных также необходимо открыть новое пространство памяти, скопировать исходный документ блога и обновить все индексы, что требует большего взаимодействия с вводом-выводом и может повлиять на производительность записи.

        必须注意的是,只有高写入流量的情况下才可能会影响写性能,而对于写入流量较小的程序反而没有那么大的影响。视具体情况而定。

3. 第三个问题是当你尝试去进行评论分页的时候,你会发觉通过常规的find查询操作,我们只能先读取整个文档信息(包括所有评论信息),然后在程序里进行评论信息的分页
  1. соединять

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

     博客的文档设计        
     {
       _id: 1,
       title: "An awesome blog",
       url: "http://awesomeblog.com",
       text: "This is an awesome blog we have just started"
     }
    
     评论的文档设计
     {
       blog_entry_id: 1,
       name: "Peter Critic",
       created_on: ISODate("2014-01-01T10:01:22Z"),
       comment: "Awesome blog post"
     }
     {
       blog_entry_id: 1,
       name: "John Page",
       created_on: ISODate("2014-01-01T11:01:22Z"),
       comment: "Not so awesome blog"
     }
这样子设计模型有个好处是当评论信息逐渐增长的时候并不会影响原始的博客文档,从而避免了单个文档超过16MB的情况出现。而且这样子设计也比较容易返回分页评论。但是坏处的话,就是假设我们在一个博客文档下拥有非常多的评论时(比如1000条),那我们获取所有评论的时候会引起数据库很多的读操作
  1. Блокировать

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

     博客的文档设计        
     {
       _id: 1,
       title: "An awesome blog",
       url: "http://awesomeblog.com",
       text: "This is an awesome blog we have just started"
     }
    
     评论信息的文档设计
     {
       blog_entry_id: 1,
       page: 1,
       count: 50,
       comments: [{
         name: "Peter Critic",
         created_on: ISODate("2014-01-01T10:01:22Z"),
         comment: "Awesome blog post"
       }, ...]
     }
     {
       blog_entry_id: 1,
       page: 2,
       count: 1,
       comments: [{
         name: "John Page",
         created_on: ISODate("2014-01-01T11:01:22Z"),
         comment: "Not so awesome blog"
       }]
     }

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

     什么时候使用分块策略?
     当你可以将文档切割成不同的批次时,那么采用这种策略可以加速文档检索
     典型的例子就是根据小时、天数或者数量进行评论分页(类似评论分页)

Модель отношений «многие ко многим»

Модель отношений «многие ко многим», на примере автора и книги


В реляционных базах данных мы можем иметь дело с промежуточными таблицами.

  1. двухстороннее вложение

    В MongoDB мы можем добавлять внешние ключи двух документов к документам друг друга через поля массива посредством двунаправленного вложения

     作者信息的文档设计
     {
       _id: 1,
       name: "Peter Standford",
       books: [1, 2]
     }
     {
       _id: 2,
       name: "Georg Peterson",
       books: [2]
     }
    
     书籍信息的文档设计
     {
       _id: 1,
       title: "A tale of two people",
       categories: ["drama"],
       authors: [1, 2]
     }
     {
       _id: 2,
       title: "A tale of two space ships",
       categories: ["scifi"],
       authors: [1]
     }
当我们进行查询的时候,可以通过两个维度互相进行查询

    通过指定的作者搜索对应的书籍
    var db = db.getSisterDB("library");
    var booksCollection = db.books;
    var authorsCollection = db.authors;

    var author = authorsCollection.findOne({name: "Peter Standford"});
    var books = booksCollection.find({_id: {$in: author.books}}).toArray();

    通过指定的书籍搜索对应的作者
    var db = db.getSisterDB("library");
    var booksCollection = db.books;
    var authorsCollection = db.authors;

    var book = booksCollection.findOne({title: "A tale of two space ships"});
    var authors = authorsCollection.find({_id: {$in: book.authors}}).toArray();
  1. одностороннее вложение

    Стратегия односторонней вложенности используется для оптимизации производительности чтения в реляционных моделях «многие ко многим» путем замены двунаправленных ссылок на однонаправленные ссылки типа «один ко многим». Эта стратегия имеет определенные сценарии.Например, в нашем случае, в разработанном нами документе с информацией об авторе информация о книге встроена в документ об авторе в виде поля массива, но на практике количество книг будет быстро расти, и это очень вероятно, что это нарушит ограничение в 16 МБ для одного документа.

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

     书籍分类的文档设计
     {
      _id: 1,
      name: "drama"
     }
    
     通过外键关联对应分类的书籍信息文档设计
     {
       _id: 1,
       title: "A tale of two people",
       categories: [1],
       authors: [1, 2]
     }

    Соответствующий оператор запроса выглядит следующим образом

     通过指定书籍来查找对应的书籍分类
     var db = db.getSisterDB("library");
     var booksCol = db.books;
     var categoriesCol = db.categories;
    
     var book = booksCol.findOne({title: "A tale of two space ships"});
     var categories = categoriesCol.find({_id: {$in: book.categories}}).toArray();    
    根据指定书籍分类来查找对应书籍
    var db = db.getSisterDB("library");
    var booksCollection = db.books;
    var categoriesCollection = db.categories;

    var category = categoriesCollection.findOne({name: "drama"});
    var books = booksCollection.find({categories: category.id}).toArray();

需要注意的地方:

    保持关联关系的平衡
    当多对多关系模型里,有一个模型数量级别特别大(比如最多可达500000个),另一个数量级别特别小(比如最多3个),像这个案例中,可能才3个左右的书籍分类就可以对应到高达500000本书。在这张数量级别悬殊的情况下,就应该采用这种单向嵌套的策略。如果双方书籍级别都比较小(可能最多也就是5个左右)的时候,采用双向嵌套的策略可能会好一点。