Обзор MongoDB: преимущества и недостатки

Сегодня за 2 часа написал великолепнейшую RSS-читалку. На Ruby. Web-фреймворк - Sinatra. База данных - MongoDB.

О впечатлениях от Монги и хочу рассказать. Работать с этой СУБД невероятно приятно и легко. Никаких таблиц, схем и миграций. Пришел. Увидел. Закодил.

Например, вот как выводится список последних 100 новостей, отсортированных по времени:

get '/news' do
news = db.collection('news').find.sort(:ts => :desc).limit(100)

erb :news,
:layout => :layout,
:locals => {
:title => 'Новости',
:news => news
}
end

В хэше news уже содержатся заголовки, описание, дата, теги, примечания и т.п. В шаблоне остается запилить перебор и отображение всех элементов news. Поскольку нет нужды продумывать нормализацию данных в БД и потом выдумывать всякие хитрожопые джоины, читалку удалось написать за пару часов. И это с Аяксом и прочими модными украшательствами. Я очень доволен.

Потом вдруг решил прогнать тесты на производительность. Тут вся эйфория и улетучилась. ab -c 100 -n 10000 показал всего 140 запросов в секунду. Это при том, что статика на этом же сервере выдается со скоростью 8300 запросов в секунду, а MySQL/PHP в похожих условиях выдает 3500 запросов в секунду. Но даже не это больше всего расстроило. Зацените потребление ресурсов. Напомню, это все тратится на "детскую" нагрузку в 140 страниц в секунду на компе с i5 и 4 Гб ОЗУ:

2238 mongodb 20 0 509m 40m 11m S 96,0 1,1 3:07.02 mongod
8224 architec 20 0 111m 38m 2180 S 47,8 1,0 0:11.05 ruby
8216 architec 20 0 111m 38m 2216 S 43,5 1,0 0:10.64 ruby
8239 architec 20 0 113m 40m 2184 S 42,5 1,0 0:10.27 ruby
8207 architec 20 0 111m 38m 2196 S 41,2 1,0 0:10.95 ruby
7052 architec 20 0 175m 41m 2220 S 40,8 1,1 1:10.84 ruby
8232 architec 20 0 111m 38m 2240 S 40,5 1,0 0:10.60 ruby
6013 root 20 0 120m 6308 3268 S 17,6 0,2 0:37.84 PassengerHelper
7296 www-data 20 0 362m 5192 1676 S 6,0 0,1 0:02.48 apache2
7997 www-data 20 0 362m 4984 1580 S 5,6 0,1 0:02.44 apache2
8078 www-data 20 0 426m 4972 1580 S 5,6 0,1 0:02.17 apache2

Узкое место - Mongo. Что имеем:
1. MongoDB - прекраснейшая СУБД, программировать под которую одно удовольствие.
2. MongoDB не всегда годится на роль замены MySQL. Особенно, если ваш web-проект не предусматривает выделение под MongoDB двух и более отдельных серверов (есть мнение, что только в такой конфигурации начинает раскрываться весь вычислительный потенциал Монги).

Оценка: 
4
Средняя: 4 (2 оценки)

Комментарии

И вообще, этот Монга какой-то стремный. Даже без нагрузки в top на первой строчке постоянно.

Оценка: 
Пока без оценки

PostgreSQL 9.4 документо-ориентированнее по объёму данных в одной записи (16 мб на запись в Монго и 1 Гбайт в Постгрес)... Ах...

Причём PostgreSQL позволяет организовать поиск по табличке с учётом вероятных фильтров в разрезе реляционных полей и добавить какие-то "не формализованные" документные данные в отдельное поле:


CREATE TABLE "test"
(
"id" serial NOT NULL PRIMARY KEY,
"title" character varying(255) NOT NULL,
"filter_id" integer NOT NULL,
"detail" jsonb
);
CREATE INDEX "test_title" ON "test" ("title");
CREATE INDEX "test_title_like" ON "test" ("title" varchar_pattern_ops);
CREATE INDEX "test_filter_id" ON "test" ("filter_id");

Ну и хренакаем всё, что не так важно в быстром поиске в поле "detail"...
А потом:


SELECT * FROM "test"
WHERE "filter_id" BETWEEN 10000 AND 1000000
AND "detail" @> '{"company": "Magnafone"}';

Оценка: 
Пока без оценки

Это что же такое нужно хранить, чтобы 16 Мб на документ не хватило? :) В документации к Монге сказано, что размер документа в коллекции не должен превышать примерно 200 Кб. Не потому, что Монга не выдержит, а потому, что превышение будет свидетельствовать о неправильном проектировании базы данных. То есть, по коллекциям надо разносить, а не стараться запихнуть все в одну.

А вот за наводку о JSON в Postgres спасибо! Востребованная фича. Надо только протестировать ее на скорость.

и 1 Гбайт в Постгрес

Представил себе такую «табличку». Двадцать записей и хостинг лег. :)

Оценка: 
Пока без оценки

Это что же такое нужно хранить, чтобы 16 Мб на документ не хватило?

Цена товара для каждого клиента от нескольких поставщиков, например: 100 поставщиков * 1000 клиентов — с длинными идентификаторами клиентов легко за 16 метров выйти. Такое нельзя организовать простой реляционкой — слишком долгий поиск по названию будет, если у каждого поставщика будет по 10000 товаров.

Вот пример плохой тяжёлой таблицы:

CREATE TABLE good (
id serial NOT NULL,
supplier_id integer NOT NULL,
client_id integer NOT NULL,
code varchar(50) NOT NULL,
title varchar(255) NOT NULL,
price numeric(10,2) NOT NULL DEFAULT 0,
)

А вот пример лёгкой таблицы:

CREATE TABLE good (
id serial NOT NULL,
supplier_id integer NOT NULL,
code varchar(50) NOT NULL,
title varchar(255) NOT NULL,
prices jsonb NOT NULL DEFAULT '{}',
)

Представил себе такую «табличку». Двадцать записей и хостинг лег. :)

Понятное дело, что получать полностью такое поле не стоит, а только конкретные данные из него.

Оценка: 
Пока без оценки

Комментировать

Filtered HTML

  • Use [fn]...[/fn] (or <fn>...</fn>) to insert automatically numbered footnotes.
  • Доступны HTML теги: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd> <blockquote> <strike> <code> <h2> <h3> <h4> <h5> <del> <img>
  • Адреса страниц и электронной почты автоматически преобразуются в ссылки.
  • Строки и параграфы переносятся автоматически.

Plain text

  • HTML-теги не обрабатываются и показываются как обычный текст
  • Адреса страниц и электронной почты автоматически преобразуются в ссылки.
  • Строки и параграфы переносятся автоматически.