Почему мы выбрали MongoDB

    Эта статья появилась на свет после прочтения материала «Почему вы никогда не должны использовать MongoDB». Ниже — история о том, как мы постепенно отказались от MySQL и пришли к использованию MongoDB в качестве основного хранилища данных.



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

    Первым делом были сформулированы:

    Требования


    В основном это требования именно к базе данных.
    Из существенных можно выделить:

    Требование 1. Мультиязычные поля


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

    Вариант 1. Две таблицы на всю базу


    create table name (
      id          int          not null primary key,
      table       varchar(32)  not null,
      field       varchar(32)  not null,
      object_id   int          not null,
      name        varchar(255) not null,
      lang        varchar(2)   not null
    )
    create table description (
      id          int          not null primary key,
      table       varchar(32)  not null,
      field       varchar(32)  not null,
      object_id   int          not null,
      description text,
      lang        varchar(2)   not null,
    )
    

    Соответственно, если у игры (таблица game) есть мультиязычное имя name, альтернативное имя alt_name и описание desc, то получилось бы, помимо самой игры, еще три записи на язык.

    Пример записей в таблице name:
    id | table | field    | object_id | name      | lang
    ---|-------|----------|-----------------------|-----
    1  | game  | name     | $game_id  | $name     | en
    2  | game  | alt_name | $game_id  | $alt_name | en
    


    Пример записи в таблице description:
    id | table | field | object_id | description | lang
    ---|-------|-------|-----------|-------------|-----
    1  | game  | desc  | $game_id  | $desc       | en
    


    Так же таблицы можно было бы объединить в одну, используя для хранения названий тип text, но мне это решение не нравилось; почему — уже не помню.

    Вариант 2. Для каждой основной таблицы — своя мультиязычная


    Для той же таблицы игр получится примерно следующее:
    create table game_i18n (
      id          int          not null primary key,
      game_id     int          not null,
      name        varchar(255) not null,
      alt_name    varchar(255) not null,
      description text,
      lang        varchar(2)   not null
    )
    

    Пример записи:
    id | game_id  | name     | alt_name     | desc     | lang
    ---|----------|----------|--------------|----------|-----
    1  | $game_id | $name    | $alt_name    | $desc    | en
    2  | $game_id | $name_ru | $alt_name_ru | $desc_ru | ru
    


    Вариант 3. Мультиязычные поля сохранять в виде json-массива в отдельном поле основной таблицы


    create table game (
      id   int not null primary key,
      ...,
      i18n text
    )
    

    Пример записи:
    id | i18n
    ---|--------------------------------
    1  | {'name':[{'lang':'en','value': $name}, {'lang':'ru','value':$name_ru}], 'alt_name': [...], 'desc': [...]}
    

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

    В итоге мы остановились на варианте 2. Против первого варианта было то, что у мультиязычных полей могут быть свои дополнительные поля. Например, в играх нужна возможность пометить одно из названий как главное, у других объектов может быть свой набор дополнительных полей, по которым, вполне возможно, еще и нужно будет фильтровать/сортировать. Не хотелось в итоге при выборе первого варианта через пару лет прийти вот к такому:
    create table name (
      id           int          not null primary key,
      table        varchar(32)  not null,
      field        varchar(32)  not null,
      object_id    int          not null,
      name         varchar(255) not null,
      lang         varchar(2)   not null,
      field1       int,
      field2       varchar(32),
      ...,
      field9       datetime
    )
    

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

    Требование 2. Связи


    Было желание иметь возможность связать любой объект из любой таблицы с любым другим объектом с сохранением направления связи.
    Варианты примерно такие же, как в и первом требовании:

    Вариант 1. Одна таблица для всех связей базы


    create table link (
      id          int         not null primary key,
      table1      varchar(32) not null,
      object1_id  int         not null,
      table2      varchar(32) not null,
      object2_id  int         not null
    )
    

    Пример записей:
    id | table1  | object1_id | table2 | obect2_id |
    ---|---------|------------|--------|-----------|
    1  | game    | $game_id   | genre  | $genre_id |
    2  | game    | $game_id   | game   | $game2_id |
    3  | game    | $game2_id  | game   | $game_id  |
    

    Записи #2 и #3 реализуют двунаправленную связь, запись #1 — однонаправленную от игры к жанру.

    Вариант 2. Для каждого типа связи своя таблица


    К примеру, связи между похожими играми получились бы такими:
    create table similar_games_link (
      id       int not null primary key,
      game1_id int not null,
      game2_id int not null
    )
    

    и так далее для каждого типа связи.

    Вариант 3. Храним связи в самом объекте в текстовом виде


    create table game (
      id    int not null primary key,
      ...,
      links text
    )
    

    Пример:
    id | links                            |
    ---|----------------------------------|
    1  | #game:$game2_id#genre:$genre_id# |
    

    Тогда можно будет искать как-то так:
    select id from game where links like '%#game:$game2_id#%'
    


    Вариант 4. Аналог варианта 3, но храним json


    Пример:
    id | links                                                                                    |
    ---|------------------------------------------------------------------------------------------|
    1  | [{'table':'game', 'object_id': $game2_id}, {'table': 'genre', 'object_id': $genre_id}]   |
    


    Варианты 5 и 6. Для каждого типа связи свое поле.


    Вариация вариантов 3 и 4, но связи раскидываются по разным полям.
    create table game (
      id      int not null primary key,
      ...,
      similar text,
      genres  text
    )
    

    В итоге решили хранить все в одной таблице (удобно же), плюс, в отдельных случаях можно было бы дублировать информацию о связях в полях самого объекта (варианты с третьего по шестой). Плодить для каждого типа связи свою таблицу не хотелось, и помочь мог третий вариант. Конечно, делать links like '%#game:$game2_id#%' — это ужасно, но я бы пережил. Отказались же от этого варианта потому, что удаление записей превращалось в нетривиальную задачу. Четвертый и шестой варианты сами по себе вообще бесполезны.

    Требование 3. Объекты с разным набором полей в одной таблице


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

    Способы решения, как хранить метаданные, те же самые, что и выше. Создается одна таблица, в которой будут общие для всех типов записей поля. А далее вариантов немного. Можно хранить все метаданные прямо в тексте поста (или в отдельном текстовом поле) специальными тегами, как это сделано в Википедии, а при сохранении раскидывать по связанным вспомогательным таблицам. Можно сразу создать вспомогательные таблицы для каждого из типов поста и сохранять метаданные туда (этот вариант мы и выбрали, тем более что для разных типов постов все равно создавались разные формы редактирования в админке). Можно хранить метаданные в виде json или любом другом сериализованном виде (проблемы тоже все те же — сложность изменения таких сериализованных данных средствами SQL, плюс сортировки/фильтрации).

    Требование 4. Сложные объекты


    Игра может быть выпущена на разных платформах и для каждой платформы может иметь разные издания. У релиза на платформе и у издания есть набор полей, совпадающий с самой игрой. Пример такого поля — «Название», так как, например, название издания для конкретной платформы может отличаться от каноничного названия игры. Также у платформы и издания есть набор полей, которых нет в самой игре, например, для платформы это будет собственно сама платформа, у издания — дата его релиза. Как все это хранить? В виде трех раздельных таблиц? По аналогии с тем, как решается хранение объектов с разным набором полей в требовании 3? Или хранить саму игру в виде одной записи, а все платформы и издания — в виде json в отдельном поле этой записи? И как такую радость редактировать? Делать три разные формы? У той же Pac-Man 27 платформ и более 30 изданий, редактирование такого монстра может превратиться в пытку. А как это показывать? Например, чтобы показать издание, придется для него загрузить платформу и саму игру, потому что, например, у издания может не быть своего названия. Тогда нужно смотреть общее название игры на платформе, а если там его нет, то смотреть название самой игры. При этом заранее прописать всем изданиям совпадающее название — тоже не здорово.

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

    MySQL


    Определившись с требованиями и предварительными вариантами их решения, мы начали разрабатывать админку. И тут (впрочем, как и всегда) начались проблемы. Например, у компании может быть название и описание. Создаем одну таблицу company_i18n с полями name и description. Пока все идет хорошо. В форме редактирования

    HTML форма:
    Название                     Описание
    en: Bad Pixel [x]            ru: Тут длинное описание на русском [x]
    ru: ООО “Бед Пиксел” [x]     [добавить описание]
    [добавить название]
    

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

    Записи в company_i18n после сохранения:
    id | lang | name             | description
    ---|------|------------------|--------------------------------
    1  | en   | Bad Pixel        | NULL
    2  | ru   | ООО “Бед Пиксел” | Тут длинное описание на русском
    

    Потом оказалось, что описаний на одном языке может быть несколько, а название должно быть строго одно для языка, и мы приходим к чему-то типа:
    id | lang | name             | description
    ---|------|------------------|------------
    1  | en   | Bad Pixel        | NULL
    2  | ru   | ООО “Бед Пиксел” | Описание 1
    3  | ru   | NULL             | Описание 2
    

    Уже не очень хорошо выглядит, особенно если нужно удалить “Описание 2” с помощью SQL — нужно смотреть, есть ли название в поле name, и если оно есть, обновлять запись, а если нет, то удалять. Потом у названия компании появляется флаг “основное”, появляется поле для корпоративных названий, которых может быть несколько на одном языке (для разных периодов времени свое), и приходит понимание, что, похоже, придется хранить имена и описания в разных таблицах.

    У связей между объектами почти сразу появилась сила связи. Это не было проблемой, проблемы начались, когда для разных типов связей появился свой набор дополнительных полей. Например, жанры могут быть связаны с другими жанрами и являться их поджанрами, и связь должна быть двунаправленной: в тегах одни теги являются персонажами из другого тега-вселенной, а у игр одна и та же компания может быть как разработчиком, так и издателем. И хотя проблему можно решить, добавив новые поля в таблицу link, но правильнее будет для отдельных типов связей создавать отдельные вспомогательные таблицы.

    Я, конечно, понимаю, что жизнь — это боль, и разработчик (в частности) должен не забывать страдать, поэтому разработка медленно, но верно продолжалась, а вспомогательные таблицы появлялись с завидной регулярностью. Тем не менее, хотелось как-то автоматизировать процессы создания таких вот вспомогательных таблиц и сборки полного объекта из них. С такими мыслями в начале 2010 года я наткнулся на статью “Как FriendFeed использует MySQL для хранения данных без схемы”.

    MySQL и данные без схемы


    Идея сделать NoSQL поверх MySQL выглядит не так уж и безумно даже сейчас. На тот момент MySQL развивалась уже годами и являлась надежным решением для production, а специализированные NoSQL решения только начали появляться, и не хотелось, сделав выбор в пользу чего-то одного, через пару лет оказаться один на один с не поддерживаемым продуктом. Я думаю, те, кто, как и я в свое время, сделал ставку на prototype.js, меня поймут.

    В то время MongoDB мы даже не рассматривали по разным причинам, в частности, ее пока не рекомендовали для production (первый production ready релиз был в конце первого квартала 2010-го). Я до сих пор сторонник такого подхода: использовать для проектов относительно устоявшиеся решения и по минимуму привлекать самописные аналоги. Но тогда устоявшихся решений еще не было (или казалось, что их нет), и для одного из своих сторонних проектов я написал что-то похожее на то, что было у FriendFeed. Поймите меня правильно: я этим не горжусь — идея сделать что-то свое может быть заманчивой ровно до тех пор, пока не придется это что-то поддерживать, фиксить «баги», оптимизировать, развивать функциональность, адаптировать к новым версиям языка/библиотек/используемых сервисов. Единственное, о чем я жалею — нужно было тогда скачать и пощупать «монгу», это дело получаса, максимум часа, а пользы — на годы. Собственно, это касается всех новых технологий: появляются они не просто так, и знание современных тенденций позволяет элементарно расширять кругозор.

    Итак, была написана библиотека для работы с данными без схемы и хранением всего этого в MySQL.

    Краткое описание того, что получилось.
    Объекты хранились в сериализованном виде в blob поле таблицы entity. Было введено дополнительное поле category (аналог таблиц в MySQL и коллекций в MongoDB), чтобы можно было разделять объекты, например игры, компании и т.п. (от варианта, когда, например, все сообщения хранятся в объекте темы, мы почти сразу отказались — для сообщений своя категория, для темы своя), плюс два поля — время создания и обновления объекта. Так как писалось все на Perl, то использовалась библиотека Storable для сериализации структур данных (обычно комбинация хэшей и массивов) из внутреннего представления в бинарный вид и обратно. В первую очередь это было сделано из-за скорости, в json данные конвертировались на порядок медленнее. Во вторую — из-за более компактного представления по сравнению с json.

    В качестве id испольовался uuid, 16 байт которого кодировались с помощью base 64 в текстовую строку длиной 22 байта.

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

    Так как по таблице entity никаких запросов (кроме как по первичному ключу и категории) делать было нельзя, были введены индексы — обычные MySQL таблицы, которые создавались на основании полей сохраняемого объекта.
    CREATE TABLE IF NOT EXISTS `index_platform` (
      `generation` int(10) unsigned NOT NULL,
      `path_id`    varchar(255)     NOT NULL,
      `entity_id`  binary(22)       NOT NULL,
      KEY `generation` (`generation`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    

    В конфиге прописывалось:
    $db->index(
        'table'      => 'index_platform',
        'properties' => ['generation', 'path_id'],
        'shard_on'   => 'entity_id',
        'categories' => ['platform'],
    ));
    

    Тогда при сохранении объекта:
    my $uuid = $db->put({
        'generation' => 0,
        'path_id'    => 'pc',
        'name'       => [
            {'lang' => 'en', 'value' => 'PC'}
        ]
    });
    

    В index_platform автоматом создавалась запись:
    generation | path_id | entity_id
    -----------|---------|----------
    0          | pc      | $uuid
    


    По этим индексам уже можно было делать выборки:
    $db->resultset('index_platform')->search({
        path_id    => {'in' => ['pc', 'xbox']},
        generation => {'in' => [0, 1]}
    },
    {
        order_by   => 'generation desc',
        limit      => 10,
        page       => 2,
        join       => 1 # с этим любые поля, содержащие первичный ключ из таблицы entity, превращались в объект, на который они ссылаются
    })->all();
    


    Альтернативный вариант того же самого запроса:
    $db->resultset('index_platform')->search({
        path_id    => {'in' => ['pc', 'xbox']},
        generation => {'in' => [0, 1]}
    })->order_by('generation desc')->limit(10)->page(2)->join(1)->all();
    


    Существовало только два типа взаимодействия с БД: это изменение самих объектов в таблице entity (включая удаление) и запросы к индексам как в примере выше. JOIN только программный.

    При удалении объекта он только помечался как удаленный, физически не удаляясь из таблицы entity.


    Примерно к середине 2010-го попробовали перейти на этот способ хранения данных.

    Объекты теперь можно было сохранять вот в таком виде:
    $company = {
        'name'        => [
            {'lang'     => 'ru',   'value' => 'ООО “Бед Пиксел”', 'is_primary' => true},
            {'lang'     => 'en',   'value' => 'Bad Pixel'},
        ],
        'description' => [
            {'lang'     => 'ru',   'value' => 'Тут длинное описание на русском”'},
        ],
        'link'        => [
            {'category' => 'tags', 'id'    => $tag_uuid,          'degree'     => 3},
            {'category' => 'game', 'id'    => $game_uuid,         'role'       => 'developer'},
        ]
    };
    

    По полю name и link автоматически создавались записи в индексных таблицах index_name и index_link. Объекты могли быть любой сложности и вложенности, с разным набором полей для объекта из одной category. Приходилось по-прежнему создавать индексные таблицы, но стало гораздо проще. Если какого-то поля не хватало, достаточно было поменять код, а если по этому полю нужно было делать выборки — создавалась дополнительная индексная таблица или менялась существующая. Если какой-то индекс не устраивал, его можно было просто удалить и построить новый. В перспективе я хотел сделать создание таких индексных таблиц автоматически по описанию их структуры в коде.

    У такого хранения данных (хранилища) наряду с плюсами были и существенные минусы.
    Из плюсов можно было выделить:
    • наличие транзакций (правда, для меня это было не так важно)
    • существование патча для mysql, который позволял обрабатывать до 750 тысяч чтений в секунду по первичному ключу
    • масштабируемость — архитектура не мешала шардить данные по первичному ключу, при этом для приложения, работающего с хранилищем, ничего не менялось
    • так как в качестве первичного ключа использовался uuid, можно было безболезненно проводить слияние сколь угодного количества баз без коллизий по первичному ключу
    • генерация индексных таблиц налету

    Основные минусы:
    • нужно самостоятельно развивать и поддерживать код самого хранилища
    • отсутствие поддержки для различных языков
    • отсутствие атомарных операций над данными; чтобы сделать $company->{'link'}->[0]->{'degree'}++, нужно загружать объект в приложение, менять и сохранять обратно в базу
    • невозможно одним запросом изменить несколько записей, только через map-функцию в стороннем приложении
    • транзакции, масштабируемость, генерацию индексных таблиц нужно было еще реализовать
    • отсутствие консоли


    В процессе эксплуатации вылезали разные «баги» самого хранилица, из наиболее неприятных — зависимость алгоритма сериализации объектов в библиотеке Storable от операционной системы. Это решили переходом на хранение объектов в виде json со сжатием с помощью gzip. Кстати, именно во время исправления этого «бага» я четко осознал, что не важно, как хранятся сами объекты. Это может быть отдельная таблица в базе данных, а можно сохранять тупо в виде json файлов, назвав их по первичному ключу и раскидывая по подпапкам (впрочем, это лишает само приложение масштабируемости, будут возникать проблемы из-за race condition и т.п., хотя, с другой стороны, можно было бы попробовать Hadoop, но, откровенно говоря, это было бы уже лишним). Главное — иметь возможность для объектов создавать индексы, как это сделано, например, в поисковой системе Sphinx. Почему бы не воспринимать MySQL примерно так же, как и Sphinx? Почему бы хранение данных не представить в виде key-value хранилища, а для поиска, сортировки и выведения пользователю различных списков создавать подходящие для этого индексы в подходящих для этого сервисах? Конечно, если создается биллинг, то такой подход, мягко говоря, не очень оправдан, но web-приложения в основной своей массе менее требовательны к наличию того же ACID, а мучаться приходится почти так же, как и с биллингом.

    Тем не менее, постепенно минусы при использовании самописного хранилища начали перевешивать, а также по-прежнему для каждого объекта нужно было рисовать свою форму в админке, одним словом — не было той универсальности, которой хотелось. Плюс ко всему на AG в 2012 году произошел ряд скорее политических событий, таких как смена владельца сайта, руководства и менеджмента, и было принято решение писать вторую версию на языке Python, поскольку программисты в новой компании писали именно на этом языке. Вариантов было два — либо текущее хранилище оформлять как standalone сервис, либо использовать какое-либо существующее key-value хранилище.

    MongoDB


    Как бы вы себя чувствовали, если бы однажды оказалось, что кто-то создал аналог вашей библиотеки (ну или наоборот — вы создали некий аналог уже существующей библиотеки, не зная об этом), и этот аналог при сохранении существенных плюсов вашего решения еще и не обладал его минусами? Лично я порадовался. Великолепная консоль с полноценной поддержкой Javascript, атомарные операции, шардинг, автоматическое создание индексов по выбранным полям, библиотеки для основных языков программирования… На тот момент уже существовали фреймворки на Python, которые поддерживали MongoDB или были написаны специально под нее. И все это не нужно было ни поддерживать, ни развивать. Да вдобавок еще и api было похоже на api хранилища.

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

    Закончить хотелось бы вот чем. Наверное, неправильно противопоставлять MongoDB и MySQL, ибо для разных задач они подходят по-разному, и так уж получилось, что в этом проекте нам больше подошла MongoDB. Если вдруг такое случится и станет не хватать скорости или функциональности MongoDB — ничто не помешает использовать MySQL в качестве кэширующей прослойки / индекса для данных — один раз настроить и забыть.

    Similar posts

    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More
    Ads

    Comments 96

      0
      Если вдруг такое случится и станет не хватать скорости или функциональности MongoDB — ничто не помешает использовать MySQL в качестве кэширующей прослойки / индекса для данных — один раз настроить и забыть.

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

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

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

        Сфинкс уже используем и в принципе я буду до последнего стараться работать именно с ним.
          +7
          попробуйте посмотреть в сторону elasticsearch. Не сфинксом единым
          +7
          У Монги один недостаток — это общий лок на коллекцию.

          В версии 2.8 лок будет на документ. Для экстремалов есть патч начиная с версии 2.7.3.
          Я, если честно, не считаю это недостатком, это скорее упущение, и скорее намеренное. Они не делали сразу лок на документ из за нехватки ресурсов и времени, да и возможно не нужно было столько операций в секунду в тот момент.
          Могу ошибиться, но разве MyISAM не блокируется на таблицу (читай как коллекцию)?
            +1
            >В версии 2.8 лок будет на документ.
            хорошая новость… но мы ушли с версии где-то 2.3

            >Могу ошибиться, но разве MyISAM не блокируется на таблицу (читай как коллекцию)?
            а кто-то из тех, кому нужна производительность, пользуется MyISAM?
              +3
              С версии 2.3 много чего изменилось. Попробуйте. Может и понравится.
              На счет MyISAM. Я как бы о том что в современном мире лок на таблицу применяется и ни кто это не ставит в упрек MySQL. А на счет производительности. Разве MyISAM не быстрее на чтение? Разные задачи, разные движки, разные решения.
              Да и вообще все это лирика и холивар без хорошей конкретизации задачи.
                0
                > Разве MyISAM не быстрее на чтение?
                если его постоянно не лочить :)
                >Да и вообще все это лирика и холивар без хорошей конкретизации задачи.
                что верно, то верно
                  –2
                  > Разве MyISAM не быстрее на чтение? Разные задачи, разные движки, разные решения.

                  Это давно не так.

                  MyISAM сейчас используют либо legacy приложения, либо для очень специфических случаев.
              +1
              Лок на коллекцию — это особенность, с которой надо просто научиться жить — читать могут сразу все, писать только один. Для снижения очередей записи помогает грамотно подобранный шардинг и архитектура базы. В нашей системе скорость записи до 200-1000 операций записи в секунду в одну коллекцию. Подходящий шард-ключ и денормализация данных нивелируют однопоточную запись. С выходом 2.8, возможно, получится отказаться от некоторых велосипедов.
                +1
                А какие проблемы с этим локом? Один фиг коллекция на моем железе обновляется со скоростью примерно 1000 в секунду. Разве этого мало? Постгрес без лока на таблицу обрабатывает гораздо меньше, и толку спрашивается?
                  –2
                  Слово durability ни о чем не говорит? Запись в /dev/null вообще по скорости порвет всех.
                    +2
                    Во-первых как durability связано с локом? Во-вторых у меня включено журналирование, так что с durability у меня все равно хорошо.
                      0
                      Странно что вы не понимаете:
                      Время единичной записи на диск порядка 8 мс на обычном диске. Последовательная запись делается быстрее, но до 1000 раз в секунду далеко. И то если жестко оптимизировать запись.

                      При этом write ahead log требует двух операций записи — в лог и на диск.

                      Космические скорости дотигаются тем, что монга не пишет на диск, а говорит ОК как только запрос получен. То есть в лог еще ничего не записано. Запросы из-за лока выстраиваются а очередь, а приложение считает что оно реально пишет 1000 документов в секунду.

                      В субд с durability нельзя вернуть из субд ОК, пока не произошла запись лога на диск. Это аналогично journaled write concern в монге. Для честного сравнения поставь journaled и сделай пару индексов. 1000 в секунду упадет до 50, зато появится гарантия что запись действительно записала.

                      Кстати в sql server, используя bulk insert с коммитом по 5000 записей и tablock мне легко удавалось делать по 20,000 записей в секунду в heap table без индексов. Это почти такой же сценарий, как предлагает mongo по умолчанию. Так чтобмонга завидный тормоз в этом плане.
                        0
                        Не правда, монга говорит ОК только после того, как данные записанны и в память и в лог. Файлы данных обновляются отложенно и восстанавливаются из лога в случае краша. Таким образом монга обеспечивает durability. Более того такая схема никак не мешает выкинуть лок на документ, он вообще никак со схемой с логами и файлами данных не связан. Большая скорость обновления обеспечивется высокой скоростью последовательной записи на диск.
                          0
                          и ваша не правда. Монга говорит ОК в зависимости от того, как вы ее попросите, она может сказать ОК как только получила запрос. И еще не факт, что ваш запрос отработает. А может отдать ОК, когда данные лягут на диск. И еще много каких вариантов, включая ваш.
                            0
                            По умолчанию монга себя так не ведет. Даже если вы включили журналирование, то journaled write concern автоматически не включится. Вы включите journaled write concern и посмотрите на реальную скорость записи.

                            Логи кстати во всех СУБД линейно пишут, так что монга тут не инноватор, и даже далеко не впереди по скорости. Вся скорость записи монги это обман потребителя. Этот обман приводит иногда к удивительным багам.

                            Что касается локов на документ, то посмотрим как их сделают. Особо интересно как они локи на документ совместят с индексами.
                            0
                            тут важно уточнить вот какой момент — использование mmap. Редко какой SQL сейчас его не использует в продакшене. То есть транзакция коммитится тоже не на диск, а в память. Но попадание на диск гарантирует ОС, то есть потеря данных может произойти только в случае краша оси. А если включить в SQL сброс на диск по каждой транзакции, то SQL тоже ничего волшебного не покажет. Хорошо бы дождаться 2.8 с локом на документ. И посмотреть ее производительность. Не на синтетике, а на реальной нагрузке, где есть и чтения, и запись
                              0
                              SQL Server например не использует, ибо небуферизированная запись на диск быстрее mmap. На *nix по скорости mmap+fsync сравнимы с небуферизированной записью. Тем не менее во всех субд используется именно гарантированная запись логов на диск, с использованием fsync например, даже в Монге. Но если каждый клиент начнет ждать записи на дист, то 1000 записей в секунду резко превратятся в 50 записей в секунду. В РСУБД тоже есть способы отложить запись на диск и получить «космическую» скорость, но это необходимо крайне редко. А durability необходима почти всегда.
                                0
                                Последовательная запись да, профит не значителен. А при рандомных апдейтах? Мы же говорим не только о записи, но и об обновлении тоже?
                                  0
                                  Лог всегда пишется последовательно, а запись данных на диск в этом случае вообще можно откладывать до вытеснения данных из памяти (если лог не перетирается и не урезается). Проблема будет только в том, что восстановление после сбоя в таком случае будет долгим.
                                    +1
                                    Все-то вы правильно говорите) Но ведь головка еще должна доехать до того места, где этот лог находится. Диск же не только лог пишет. Что-то еще читается, а основное время уходит на перемещение головки. Наш разговор превращается в препирательство. Я не против SQL, он хорош. Я не пропагандирую делать все подряд на монге, она имеет свои особенности. Но для определенных задач монга имеет определенный профит. В нашем случае монга себя полностью оправдывает — шардинг из коробки, запись на уровне памяти, поддержка неподтвержденной записи. Есть данные, важность которых не высока, они пишутся в режиме w=0,j=0, чтобы не тратить время приложения на ожидание подтверждения записи. Скорость потока данных варьируется в зависимости от времени суток от 200 до 1000 документов в секунду. В данный момент статистика на монге такая: query — 5.5K/sec, update — 1.6K/s, insert — 800/sec. Кластер состоит из 4 шардов. В случае с SQL пришлось бы вопрос шардинга брать на сторону приложения, лично я не видел нормального шардинга на опенсорсном SQL.
                                      –1
                                      Монга точно также пишет лог, как и другие СУБД. Она только клиенту может отвечать не строго после того как лог записан, а раньше этого момента. Ваши рассуждения о головке к чему?

                                      Шардинг это очень простая вещь. Я бы не называл это преимуществом монги, монга лишь делает это прозрачно для пользователя. Но никаких достижений оно не несет. Да и потребность в шардинге во взрослых субд гораздо ниже. База на несколько ТБ для обычного SQL Server на одной машине вполне нормальное явление. Монге для такого объема понадобится 100500 шард с общим объемом памяти гораздо больше 1 ТБ, и с суммарной стоимостью серверов, на порядок превышающий стоимость железа под SQL Server.

                                      Если у вас есть данные, важность которых не высока, то вы можете в приложении складывать их в очередь и струячить в базу пачками по несколько тысяч штук или по таймауту. И неважно какая база у вас будет. Почти любая СУБД сможет в таком сценарии выдать десятки тысяч записей в секунду, а приложение не будет ничего ждать.
                                        0
                                        Да, в шардинге монги нет никакого технологического прорыва. Но он снимает этот вопрос с пользователя. В нашем случае общий объем базы 15Тб, суммарный объем потребляемой памяти в пределах 250Гб с учетом кеша, шардов, как я уже говорил, 4.
                                          –1
                                          Объем данных какой? 15 для монги может означать, что базу не шринкали никогда, а живых данных там от силы 100гб.

                                          На SQL Server с 4 дисками из ваших шардов и 250гб памяти у меня будет все летать. А разницы в цене серваков хватит на лицензии SQL Server и еще в отдохнуть съездить. Терабайтные базы на пятикратно более слабом железе у меня работали.
                                            0
                                            Может означать, а может и не означать. Где-то тут в комментариях я уже упоминал, что наша система не предусматривает удаление данных
                                              0
                                              А почему не предусматривает? Может потому что в этом случае некоторые операции дорогие слишком становятся ;)
                                                0
                                                Нет, не поэтому. Потому что ее назначение собирать и накапливать информацию
                                          0
                                          мне всё-таки кажется, что шарды нужны больше не для увеличения объема данных, а для распараллеливания запросов (чтения и записи)
                                            –1
                                            Во взрослых субд это делается просто добавлением дисков.
                                              –1
                                              я про ограничение процессора, а не дисков.
                                                –1
                                                Упереться в процессор — надо постараться. Индексы и материализованные представления позволяют все вычисления перенести на стадию записи и даже на 15ТБ можно делать агрегирующие запросы за доли секунды.

                                                В монге такое в принципе невозможно. Там любой запрос, который затрагивает хотя бы 10% документов уже нужно делать через map-reduce, который ну ооооочень небыстрый.
                      +15
                      Ураа, продолжение холивара.
                        +6
                        Третий вариант — самый гибкий, но от него почти сразу отказались, так как нужны были сортировки и фильтрация по названиям, и для этого все равно пришлось бы делать что-то аналогичное варианту 1 или 2.


                        Ехал постгрес через постгрес. Тем более что в 9.4 нормальная работа jsonb появилась с индексами и печеньками.
                          +1
                          Я тоже, когда услышал про поддержку json — порадовался за них, мне кажется это хороший вектор для развития. В нашем случае это одна из вещей, которой сильно не хватало.
                            +2
                            До JSON'а был hstore, он тоже умел в индексы.
                              +1
                              И индексы к нему тоже есть разные, под разные типы выборок: github.com/akorotkov/hstore_ops
                                +2
                                Знаем, пользуемся.
                            +2
                            Ну, в таком случае и за мускуль можно порадоваться, Света Смирнова научила его работать с JSON
                            blog.ulf-wendel.de/2013/mysql-5-7-sql-functions-for-json-udf/
                            жаль что не нативные, но и в этом тоже есть свой плюс.
                              +2
                              Почитайте про jsonb в postgres и сравните возможности.
                              Просто с json постгре уже давным-давно научилась работать.
                                0
                                Кстати не давным-давно. 2012 год, если память не изменяет.

                                Я не буду спорить, что возможностей у jsonb больше, конечно.
                            –1
                            С монго вырастают требования к серверу. Сами разработчики рекомендуют, как минимум, 3 сервера для создания кластера.
                              –1
                              На мой взгляд, монго интересно рассматривать только в виде кластера. Рекомендации разработчиков о 3 серверах наверняка связаны в обеспечением отказоустойчивости?
                                +2
                                >Сами разработчики рекомендуют, как минимум, 3 сервера для создания кластера.
                                с Кассандрой не путаешь? которая разрабатывалось как чисто кластерное решение с дублированием информации.

                                и воввсе не обязательно отказоустойчивость… Монга интересна сама по себе и как кластеное, и как серверное решение.
                                  0
                                  это вопрос мне? На мой взгляд 3 сервера — рекомендация для построение репликасета, как фейловер одного инстанса.
                                  +1
                                  3 ноды это минимум для того, чтоб отказоустойчивый replica set умел правильно определять лидера. Технически это может быть 2 настоящих узла и один легкий (арбитр).
                                    0
                                    все верно, только легкий арбитр должен быть на третьей тачке, если мне память не изменяет
                                      +2
                                      ну «должен» это вопрос того, чего вы страетесь достичь этим replica set. Например, если оба узла находяться в одном сегменте, то в принципе можно запустить арбитр на одном из узлов. Ну и в любо случае, для арбитра не нужен выделенный сервер, это легкий процесс.
                                +1
                                >> В результате, начав с нуля (уже в качестве стартапа) разработку на Python в 2013 году, мы, правильно выбрав инструменты (одним из которых была MongoDB), за квартал сделали больше, чем раньше делали за два года.

                                Это называется опыт, MongoDB здесь не является решающим фактором.
                                  +2
                                  С MySQL я бы и сейчас наверно не сделал бы быстро, слишком много накладных расходов на разработку.
                                  И если бы MongoDB была сама по себе, в вакууме — пришлось бы создавать инструменты для работы с ней (админка, orm) — это тоже сильно затормозило бы.
                                  +18
                                  Ждем через год-другой статьи «Почему вы никогда не должны использовать MongoDB» (:
                                  +7
                                  Ждал описания того, как теперь всё сделано на mongodb и почему это лучше, чем mysql
                                    0
                                    Привет, Слай.
                                    А сделано все так же как и в случае хранилища. Ничего кардинально не поменялось. Объекты выглядят практически так же как и в примере с $company. Только теперь не нужно еще вручную делать индексы, все из коробки.
                                    +5
                                    Почему вы не стали рассматривать PostgreSQL и его json и hstore типы?

                                    Сам я пришел к выводу, что Mongo крайне неудобна в виде единственной базы для приложения. PostgreSQL же позволяет объединить все плюсы MySQL и Mongo, причем строить запросы с джойнами сразу из SQL и NoSQL хранилищ, что не позволят сделать две совершенно разные базы.
                                      –6
                                      PostgreSQL хороший выбор, да, но за 11 лет работы с РСУБД я немного от них устал, по этому до рассмотрения PostgreSQL дело просто не дошло.
                                        +1
                                        А с какими ещё РСУБД вам приходилось работать? :)

                                        Всё-таки PostgreSQL — это не просто реляционная, это объектно-реляционная СУБД. И мне достаточно сложно представить, как она может выпасть из рассмотрения.
                                          +1
                                          С разными приходилось, сейчас вот приходится работать firebird. Но наверно 99% времени я работал с MySQL.

                                          Если сравнивать PostgreSQL и MongoDB, то для меня проще работать с монгой — это наверно основная причина. Мне не нужно думать — какие данные пойдут в json, а какие в основные поля таблицы, не придется думать о миграции полей из json в поля таблицы и обратно. Не придется вообще работать с таблицами, мне нравится, что у монги есть полноценный яваскрипт в консоли, что мне не придется думать об sql injection, если я отдам какие то модули на аутсорс. Как то так.
                                        +3
                                        У SQL и noSQL разные сферы применения. Если в приложении отсутствуют или минимальны связи между сущностями, то зачем пытаться притянуть к такому приложению реляционную базу данных. Плюс у монги достаточно удобный шардинг из коробки, организация которого практически исключает единую точку отказа, если кластер построен по всем рекомендациям.
                                          0
                                          Одно приложение, как правило, содержит в себе данные либо только SQL, либо обоих сфер применения.
                                          Если это не микроприложение с крайне-узкой целью, где подойдет и чистый NoSQl.

                                          dmitriy_b > но за 11 лет работы с РСУБД я немного от них устал
                                          Желание «попробовать что-то новое» было выше, чем «сделать эффективно»?
                                            +1
                                            В любом правиле есть исключения. Представьте систему, в которой есть только две сущности — сообщение и автор. И сообщений, как и авторов, очень много (например, миллиарды). Какой смысл в такой системе от использования SQL? И можно ли такую систему считать «микроприложением»?
                                              0
                                              Какой смысл в такой системе от использования SQL?

                                              может в согласованности данных в БД?
                                                +1
                                                приложение не предусматривает удаление какой-либо информации.
                                                1. проверили наличие автора
                                                2. сохранили сообщение

                                                какую проблему согласованности ожидать?

                                                Я изначально обозначил свою позицию в этом вопросе — у SQL своя зона применения, у noSQL своя. Если у приложения нет необходимости в преимуществах SQL, а преимущества noSQL делают его более выгодным кандидатом при выборе БД, то зачем усложнять себе жизнь?
                                                Я никому не предлагаю заменить SQL на noSQL. Они оба хороши по-своему
                                                  0
                                                  Автор удалился между п1 и п2.

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

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

                                                  В комментариях к статье habrahabr.ru/post/231703/ как раз есть пример с продажей билетов, который монге не по зубам.
                                                    +1
                                                    Автор удалился между п1 и п2.

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

                                                    write concern закрутить покрепче, ну или кеш
                                                    продажные, читай транзакционные, сайты на нетранзакционной базе делать — зачем усложнять себе жизнь?
                                                    почему все так пытаются приладить монгу там, где делать этого не стоит?
                                                      0
                                                      map-reduce индексы в фоне обновляются насколько я понимаю, writeconcern им не помогает, зато роняет быстродействие монги на порядок (это я вживую видел).

                                                      Вопрос согласованности данных актуален не только при работе с деньгами.
                                                        0
                                                        Да, я не уточнил, имел в виду обычные индексы. И вообще к индексам в монге надо подходить с умом. Добавление 2 индексов (1 по одному полю, другой по трем) снизило скорость вставки с 11 тысяч до 500
                                                          +1
                                                          Без индексов любая выборка НЕ по ключу — полное сканирование документов. Если у вас документов сотни тысяч в коллекции, то это тормозит.
                                                            0
                                                            это понятно. У нас документов десятки миллионов в коллекциях. Проблему снижения производительности из-за индексов решали с помощью дополнительных коллекций. С учетом readers-writers lock это дало нам существенный профит производительности
                                                          0
                                                          ключевым словами были транзакционные и нетранзакционные. Без упора на деньги
                                                +1
                                                «Желание «попробовать что-то новое» было выше, чем «сделать эффективно»?»

                                                Нет — мне кажется в статье видно, что еще до знакомства с MongoDB мы перешли на сходный с монгой принцип хранения данных. Монга была не чем то новым, а скорее ответом на наши потребности.
                                                0
                                                единая точка отказа — это mongos
                                                  0
                                                  если у вас 2+ серверов приложений, то ставьте по монгосу на каждый из них. Монгос — это просто роутер. А если у вас один сервер приложения, то у вас в первую очередь точкой отказа является он. Конфигсвр также не является единой точкой, в продакшене рекомендуется использовать 3 конфигсвра
                                              +1
                                              > Еще одним из, как мне кажется, правильных решений был выбор админки, которая позволяла редактировать объекты любой вложенности

                                              Как называется админка, если не секрет?
                                                +3
                                                В качестве API: python-eve
                                                Фронтенд: backbone-forms — большой плюс — поддержка вложенных форм.
                                                Выглядит все это как то так:
                                                +7
                                                Из требований не увидел ровным счётом НИЧЕГО, что просто требовало бы NoSQL.
                                                Ребята, вы занимаетесь натягиванием задач на технологию, а не применением технологии для решения задачи! Подрастёте — появится понимание, что игры в новомодные баззворды — удел студентов с «бесконечным» временем, а в реальной работе нужны чёткие, проверенные решения.
                                                И главное, кого и в чём вы хотите убедить своей статьёй? Вы СЕБЕ хотите доказать, что не ошиблись? Это называется патологическое враньё, от него нужно лечиться.
                                                  –3
                                                  Сложно комментировать, когда за тебя уже все решили и до кучи еще и диагноз поставили, но я всетаки попробую.

                                                  Статья называется «Почему мы выбрали MongoDB».
                                                  Выбор основан не столько на требованиях, сколько на удобстве разработки в соответствии с требованиями.
                                                  Эту же задачу можно решить вообще без использования SQL/NoSQL решений, но зачем? Вопрос в удобстве, нам удобнее так и в статье описывается почему.
                                                    +4
                                                    Вы же сами себе противоречите в одном и том же предложении!

                                                    > Выбор основан не столько на требованиях, сколько на удобстве разработки в соответствии с требованиями.

                                                    Так учитываются «требования» или нет??
                                                    Логически рассудите: требование — «хранить разнородные записи». Решение — «берём РСУБД и создаём таблицы» — потому что это классическое, проверенное временем решение на ТЫСЯЧАХ систем. Вы от него отказываетесь. Причина? «Мне не нужно думать — какие данные пойдут в json, а какие в основные поля таблицы, не придется думать о миграции полей из json в поля таблицы и обратно. Не придется вообще работать с таблицами, мне нравится, что у монги есть полноценный яваскрипт в консоли, что мне не придется думать об sql injection...» (к слову, о половине этой белиберды я вообще не думаю — просто решаю задачу)
                                                    Другими словами, это даже не «технический выбор», а чисто субъективное «мне не надо думать» (хотя я не понимаю, как можно «не думать» там, где как раз всё ядро системы!). Сунете вы данные в Mongo или SQL, всё-равно придётся заботиться о многих вещах, от консистентности данных до производительности, балансировки нагрузки и шифрования.
                                                    Кратко говоря, вы даже не выбирали, а просто «мне так удобно» и бац — поставили MongoDB! И _это_ заслуживало отдельной статьи??? :))) Я потому и написал «диагноз» (разве он не верен?), что ДАЖЕ если у вас были какие-то технические соображения, в этой многословной статье я их не увидел.

                                                    «Технический выбор» — это когда:
                                                    «Мы сделали реляционные таблицы (схема), в нашей задаче нужно выбрать список бла-бла… получилось вот такое решение (SQL запрос/ORM, объекты) с такими затратами по памяти/времени и вот такими перспективами под будущие нужды. А теперь мы перенесём это в NoSQL — получилась вот такая выборка, вот на столько стало МЕНЬШЕ(?) кода/времени/памяти и вот так увеличилась гибкость по расширению системы». Если бы я это прочёл, я бы выкинул нафик все свои базы, побрил голову (так принято) и пошёл к вам в ученики. :) Но ничего этого я не увидел, поэтому и написал своё мнение: ваш выбор сугубо индивидуальный и не показывает НИКАКИХ преимуществ, почему нужно делать решение именно на NoSQL.
                                                      –3
                                                      «Так учитываются «требования» или нет??»

                                                      Конечно учитываются. Еще раз — выбор пал на монгу из за того, что в свете изложенных выше требований с ней легче работать.
                                                      Не быстрее, не правильнее, а легче.

                                                      «вот на столько стало МЕНЬШЕ(?) кода/времени/памяти и вот так увеличилась гибкость по расширению системы»

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

                                                      «ваш выбор сугубо индивидуальный»

                                                      Именно так.

                                                        +6
                                                        > «ваш выбор сугубо индивидуальный» — Именно так.

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

                                                        Требование 1. Мультиязычные поля

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

                                                        Требование 2. Связи

                                                        Опять же, даже вы сами указали несколько решений, все они приемлемы в зависимости от требований задачи. И к слову, NoSQL тут вообще ничем не помогает: docs.mongodb.org слэш manual/reference/database-references/ — такое же «костыльное» решение как у обычного SQL.

                                                        Требование 3. Объекты с разным набором полей в одной таблице

                                                        Ради бога! Не путайте «нам нужно вывести список на страничку» с «нам нужно всё хранить в одной таблице» — это РАЗНЫЕ вещи. Никто не мешает получить десять списков РАЗНЫХ объектов и вывести хронологически, LINQ вам в помощь.

                                                        Требование 4. Сложные объекты

                                                        Ну сложные, и чо? Та сумбурщина, которую вы описали — не повод прыгать в какие-то маргинальные решения. Тот же JSON в PostgreSQL вполне «поискуем». Я уже в курсе, что PostgreSQL не рассматривался вообще — серьёзное упущение, но всё равно никаким боком не дающее NoSQL преимуществ — весь вопрос лишь в понимании требований.

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

                                                        «Я выбрал MongoDB, потому что это модно и там есть полноценный яваскрипт в консоли» — вот и весь грустный смысл статьи. :(
                                                          –1
                                                          Локализация.
                                                          «NoSQL никаких преимуществ тут не даёт.»

                                                          С NoSQL это делать гораздо удобнее.

                                                          Связи.
                                                          «несколько решений, все они приемлемы в зависимости от требований задачи»

                                                          Проще связь хранить в самом объекте — в MongoDB это делать удобно.

                                                          Объекты с разным набором полей в одной таблице
                                                          «Ради бога! Не путайте «нам нужно вывести список на страничку» с «нам нужно всё хранить в одной таблице» — это РАЗНЫЕ вещи»

                                                          Я ничего не путаю. Я НЕ хочу их хранить в разных таблицах. Мне удобнее хранить их в одной. И проще это делать в MongoDB.

                                                          Сложные объекты
                                                          «Тот же JSON в PostgreSQL вполне «поискуем»»

                                                          Мне хватает поискуемости в MongoDB.

                                                          Итого, вы предлагаете набор разных частных решений, для того, что можно решить (и уже решено) нормально одним инструментом.
                                                            0
                                                            «Гораздо удобнее» это слишком субъективный фактор, чтобы его приводить как доказательство.
                                                              0
                                                              " его приводить как доказательство"

                                                              Так я вроде ничего и не доказываю.
                                                                0
                                                                Вы доказываете «обоснованность выбора». Увы, вы сделали эмоциональный выбор, который пытаетесь теперь рационализировать, а люди вам не верят.

                                                                Я кстати даже прекрасно понимаю почему вы выбрали Mongo — вы не умеете работать с SQL. Генерацию запросов и поддержку схемы не осилили. Я не знаю как это решается в Python, но в C# с Linq подобных проблем и близко нет.
                                                                  0
                                                                  «Я кстати даже прекрасно понимаю почему вы выбрали Mongo — вы не умеете работать с SQL»

                                                                  Я с SQL работаю больше 11 лет. И прямые запросы и orm и как угодно.
                                                                    0
                                                                    Суд по посту это не так. Вы даже при проектировании не учли ни уникальные индексы, ни композитные ключи, ни возможность джоинов по неключивым полям.
                                                                      0
                                                                      Наверно потому что это пример того, какие поля нужны были, а не реальные таблицы?
                                                                        0
                                                                        Тогда какой смысл в этом примере? Вы же сделали вид, что это схема БД, а теперь оказывается что это не схема БД, а вольные фантазии на эту тему?

                                                                        И вообще почти ни слова нет о запросах. Без этого нет смысла движки обсуждать вообще.
                                                                          0
                                                                          «Тогда какой смысл в этом примере?»

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

                                                                            1) (была какая-то задача, о которой вы не сказали)
                                                                            2) вы придумали набор полей и связей (на самом деле не явно насколько этот набор адекватен задаче)
                                                                            3) (вы сделали нечто на MySQL, об этом вы тоже не говорите почти ничего)
                                                                            4) потом сделали на MongoDB — получилось быстрее.

                                                                            То есть два ключевых момента — что сделали и почему сделали у вас не описано. А все остальное это вкусовщина.
                                                                              0
                                                                              Есть требования, варианты их решения и описан выбор который был сделан по каждому требованию для MySQL.

                                                                              Потом была миграция с MySQL на «нечто» и пример того, как стали хранится данные в этом «нечто» и насколько это стало удобнее.

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

                                                                              По крайней мере в статье я хотел описать именно это. Если это не получилось, ну чтож — значит мне нужно треннироваться яснее выражать свои мысли.
                                                                                0
                                                                                Еще раз:
                                                                                1) «Требования» являются просто фантазией, если ты не озвучил решаемую проблему в терминах потребителя.
                                                                                2) Из п1 следует что удобство в этом случае очень субъективно и скорее связано с твоим опытом, чем с реальными преимуществами.
                                                                                3) Ты же сам сослался на мой перевод про MongoDB, в нем более половины объема уделено описанию решаемых задач.
                                                  +2
                                                  Мы говорим локализация и думаем про gettext, мы говорим пр геттекст и думаем про локализацию. И не важно какое у вас хранилище воообще.

                                                  Теперь про хранилище. На что только люди не идут чтобы только не использовать PostgreSQL :)

                                                  Для уникальности записей на одном языке если уж на то пошло есть такая вещь как уникальность и составные индексы.

                                                  Хранить всё в одной табличке вам не нужно. Уверен.

                                                  Для связей есть hstore, для JSON есть JSON.

                                                  Так и не понял зачем вам нужен был NoSQL (При том условии что он не нужен вообще. )

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

                                                    Вы не правы. У нас почти сразу разделилась контентная часть и дизайн. Для дизайна удобно использовать gettext. Для контентной части нет.
                                                      0
                                                      И чем неудобно?
                                                        0
                                                        Есть у нас таблица с типами названий компании — выше на скриншоте. Там есть мультиязычное поле name, которое мы выгружаем в pot файл и отдаем на перевод, сюда бы gettext подошел.

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

                                                        Такое проще решается без gettext.
                                                    0
                                                    Проектирование любой СУБД надо начинать с того какие у вас запросы. Вы описали все что можно, кроме запросов. Я могу на тех же входных данных, что вы привели, обосновать использование абсолютно любого хранилища.

                                                    Only users with full accounts can post comments. Log in, please.