Производительность запроса реляционных данных с помощью nosql на основе документов (mongodb, couchdb, riak и т. Д.) - PullRequest
5 голосов
/ 01 октября 2011

Чтобы продолжить мой вопрос о моделировании реляционных данных с помощью nosql , я прочитал несколько статей на эту тему:

Nosql не означает нереляционный

Пример электронной коммерции Nosql

Кажется, они предполагают, что nosql может обрабатывать нормализованные реляционные данные.

Итак, давайте продолжим с примером, который у меня был ранее, системой CMS, имеющей два типа данных: статью и авторов, где статья имеет ссылку (по идентификатору) на автора.

Ниже приведены операции, которые должна поддерживать система:

  1. Получить статью по идентификатору вместе с автором
  2. Получить все статьи определенного автора
  3. Найдите первые 10 статей с авторами, отсортированными по дате создания

Я хотел бы понять производительность этих операций при сравнении с одной и той же операцией, если в СУБД хранятся одни и те же данные. В частности, укажите, использует ли операция MapReduce, требуется ли многократные поездки в хранилище nosql (ссылки) или предварительное объединение

Я бы хотел ограничиться обсуждением основанным на документе решением nosql, таким как mongodb, couchdb и riak.

Редактировать 1:

Проект Spring-data доступен на Riak и Mongodb

Ответы [ 3 ]

5 голосов
/ 03 октября 2011

Просто хотел добавить ответ CouchDB для всех, кому это может быть интересно. :)

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

CouchDB использует запросы MapReduce, обычно написанные на JavaScript (но доступны Python, Ruby, Erlang и другие). Результаты запроса MapReduce сохраняются в индексе по их первому запросу, и этот сохраненный индекс используется для всех будущих поисков. Изменения в базе данных добавляются в индекс при последующих запросах.

API CouchDB полностью основан на HTTP, поэтому все запросы к базе данных являются HTTP-глаголами (GET, POST, PUT, DELETE) по различным URL-адресам. Я перечислю оба запроса MapReduce (написанные на JavaScript) вместе с URL-адресом, используемым для запроса связанных результатов из индекса.

1. Получить статью по идентификатору вместе с автором

Самый простой способ сделать это - два прямых поиска документов:

GET /db/{article_id}
GET /db/{author_id}

... где {author_id} - значение, полученное из поля author_id статьи.

2. Получить все статьи конкретного автора

MapReduce

function (doc) {
  if (doc.type === 'article') {
    emit(doc.author_id, doc);
  }
}
GET /db/_design/cms/_view/articles_by_author?key="{author_id}"

... где {author_id} - фактический идентификатор автора.

3. Найдите первые 10 статей с авторами, отсортированными по дате создания

MapReduce

function (doc) {
  function arrayDateFromTimeStamp(ts) {
    var d = new Date(ts);
    return [d.getFullYear(), d.getMonth(), d.getDate(), d.getHours(), d.getMinutes(), d.getSeconds()];
  }

  var newdoc = doc;
  newdoc._id = doc.author_id;
  newdoc.created_at = arrayDateFromTimeStamp(doc.created_at);

  if (doc.type === 'article') {
    emit(newdoc.created_at, newdoc); 
  }
}

Возможно включить стиль "соединения" в CouchDB, используя ?include_docs=true в запросе на просмотр. Если вы добавите ключ «_id» в значение стороны emit (второй аргумент), то добавление include_docs=true к параметрам вашего запроса будет включать документ, на который ссылается указанный «_id». В приведенном выше случае мы заменяем собственный «_id» документа (который нам больше не нужен) с указанным автором «_id» (значение «author_id» в документе статьи). Запрос 10 лучших статей с информацией об авторе выглядит следующим образом:

GET /db/_design/cms/_view/articles_by_date?descending=true&limit=10&include_docs=true

Запрос этого URL вернет список 10 последних статей в формате, подобном:

{"rows":[
  { "id":"article_id",
    "key":[2011, 9, 3, 12, 5, 41],
    "value":{"_id":"author_id", "title":"..."},
    "doc":{"_id":"author_id", "name":"Author Name"}
  }
]}

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

Существуют также методы использования сопоставления представлений для объединения нескольких документов из одного документа (например, страницы в CMS, ссылающейся на разнородный контент). Есть некоторая информация о том, как сделать это на этих слайдах, которые я сделал для CouchConf в июле: http://www.slideshare.net/Couchbase/couchconfsfdesigningcouchbasedocuments

Если у вас есть другие вопросы, пожалуйста, дайте мне знать.

4 голосов
/ 01 октября 2011

Получить статью по идентификатору вместе с автором

SQL :

  • 1 запрос
  • 2поиск по индексу
  • 2 поиска по данным
  • возвращенные данные = статья + автор

MongoDB :

  • 2запросы
  • 2 просмотра индекса
  • 2 поиска данных
  • возвращенные данные = статья + автор

Получить все статьи определенного автора

SQL :

  • 1 запрос
  • 1 просмотр индекса
  • N поиск данных
  • возвращенные данные = N статей

MongoDB :

  • 1 запрос
  • 1 просмотр индекса
  • Nпоиск данных
  • возвращенные данные = N статей

Найдите первые 10 статей с авторами, отсортированными по дате создания

SQL :

  • 1 запрос
  • 2 просмотра индекса
  • от 11 до 20 просмотров данных (articтолько потом уникальные авторы)
  • возвращенные данные = 10 статей + 10 авторов

MongoDB :

  • 2 запроса (articles.find().sort().limit(10), authors.find({$in:[article_authors]})
  • 2 индекса поиска
  • от 11 до 20 просмотров данных (статьи затем уникальные авторы)
  • возвращенных данных = 10 статей + от 1 до 10 авторов

Сводка

В двух случаях MongoDB требует дополнительного запроса, но выполняет большую часть той же общей работы под ним.В некоторых случаях MongoDB возвращает меньше данных по сети (без повторных записей).Запросы на присоединение, как правило, ограничены требованием, чтобы все данные для объединения находились в одном и том же окне.Если авторы и статьи живут в разных местах, то в любом случае вы в конечном итоге будете выполнять два запроса.

MongoDB имеет тенденцию к повышению "сырой" производительности, потому что он не записывается на диск при каждой записи (так что на самом деле это "долговечность "компромисс).Он также имеет гораздо меньший синтаксический анализатор запросов, поэтому на каждый запрос меньше активности.

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

2 голосов
/ 01 октября 2011

Для MongoDB вы не будете использовать встроенные документы для записи автора.Итак, предварительное объединение вышло, это многократные поездки в БД.Тем не менее, вы можете кэшировать автора, и вам нужно будет выполнить это второе отключение только один раз для каждой записи.Указанные вами запросы довольно просты в MongoDB.

var article = db.articles.find({id: article_id}).limit(1);
var author = db.authors.find({id: article.author_id});

Если вы используете ORM / ODM для управления вашими сущностями в вашем приложении, это будет прозрачно.Это было бы две поездки в БД, хотя.Это должны быть быстрые ответы, хотя два попадания не должны быть заметны вообще.

Поиск статей данного автора просто обратный ...

var author = db.authors.find({id: author_name}).limit(1);
var articles = db.articles.find({author_id: author.id});

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

var articles = db.articles.find({}).sort({created_at: 1}).limit(10);
var author_ids = articles.map(function(a) { return a.author_id });
var authors = db.authors.find({id: { '$in': authors_ids }});

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

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

И, наконец, реальные последствия для производительности, связанные с этим ... Так как в идеале вы будете запрашивать только индексированные поля в документе, это должно быть довольно быстро.Единственный дополнительный шаг - это вторая поездка в оба конца, чтобы получить другие документы, в зависимости от структуры вашего приложения и базы данных, это, вероятно, не имеет большого значения.Вы можете указать mongo профилировать только те запросы, которые принимают заданный порог (по умолчанию 100 или 200 мс при включении), чтобы вы могли следить за тем, что занимает время для вашей программы по мере роста данных.

Единственное, что вам подходит, что RDMS не предлагает, намного проще разбить данные.Что происходит, когда вы расширяете свое приложение за пределы CMS для поддержки других вещей, но используете то же хранилище аутентификации?Теперь это просто отдельная БД, которая используется многими приложениями.Гораздо проще выполнять эти запросы через базы данных - с хранилищами RDMS это сложный процесс.

Надеюсь, это поможет вам в открытии NoSQL!

...