Обзор 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 двух и более отдельных серверов (есть мнение, что только в такой конфигурации начинает раскрываться весь вычислительный потенциал Монги).
Комментарии
pomodor
21 декабря, 2014 - 01:54
И вообще, этот Монга какой-то стремный. Даже без нагрузки в top на первой строчке постоянно.
DJ_Baldey
21 декабря, 2014 - 17:29
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"}';
pomodor
22 декабря, 2014 - 15:47
Это что же такое нужно хранить, чтобы 16 Мб на документ не хватило? :) В документации к Монге сказано, что размер документа в коллекции не должен превышать примерно 200 Кб. Не потому, что Монга не выдержит, а потому, что превышение будет свидетельствовать о неправильном проектировании базы данных. То есть, по коллекциям надо разносить, а не стараться запихнуть все в одну.
А вот за наводку о JSON в Postgres спасибо! Востребованная фича. Надо только протестировать ее на скорость.
Представил себе такую «табличку». Двадцать записей и хостинг лег. :)
DJ_Baldey
24 декабря, 2014 - 10: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 '{}',
)
Понятное дело, что получать полностью такое поле не стоит, а только конкретные данные из него.
Комментировать