MongoDB
 sql >> база данни >  >> NoSQL >> MongoDB

Последователи - дизайн на база данни mongodb

Съгласен съм с общото схващане на други отговори, че това е гранична линия релационен проблем.

Ключът към моделите на данни MongoDB е тежестта при запис, но това може да бъде сложно за този случай на употреба, най-вече поради счетоводството, което би било необходимо, ако искате да свържете потребителите директно към елементи (промяна в група, която е последвана от партиди от потребители ще понесе огромен брой записвания и имате нужда от някой работник, който да направи това).

Нека да проучим дали моделът за четене е неприложим тук, или правим преждевременна оптимизация.

Подходът за тежко четене

Вашата основна грижа е следният случай на употреба:

истински проблем с производителността може да бъде, когато искам да получа всички групи, които потребителят следва за конкретен елемент [...], защото тогава трябва да намеря всички групи, които потребителят следва, и от това да намеря всички item_groups с group_id $in и идентификатора на елемента.

Нека да разчленим това:

  • Вземете всички групи, които потребителят следва

    Това е проста заявка:db.followers.find({userId : userId}) . Ще ни трябва индекс на userId което ще направи времето за изпълнение на тази операция O(log n) или изключително бързо дори за големи n.

  • от това намерете всички item_groups с group_id $in и идентификатора на артикула

    Сега това е по-сложната част. Да предположим за момент, че е малко вероятно елементите да са част от голям брой групи. След това съставен индекс { itemId, groupId } би работил най-добре, защото можем да намалим драстично набора кандидат чрез първия критерий - ако даден елемент е споделен само в 800 групи и потребителят следва 220 групи, mongodb трябва само да намери пресечната точка на тях, което е сравнително лесно, тъй като и двете комплектите са малки.

Все пак ще трябва да отидем по-дълбоко от това:

Структурата на вашите данни е вероятно тази на сложна мрежа . Сложните мрежи се предлагат в много разновидности, но има смисъл да приемем, че графиката на последователите ви е почти без мащаб, което също е почти най-лошият случай. В мрежа без мащаб, много малък брой възли (знаменитости, супер купа, Wikipedia) привличат много „внимание“ (т.е. имат много връзки), докато много по-голям брой възли имат проблеми с получаването на същото количество внимание комбиниран .

Малките възли не са причина за притеснение , заявките по-горе, включително двупосочни пътувания до базата данни, са в диапазон от 2 мс на моята машина за разработка на набор от данни с десетки милиони връзки и> 5GB данни. Сега този набор от данни не е огромен, но без значение каква технология изберете, ще бъде обвързан с RAM, тъй като индексите трябва да са в RAM във всеки случай (местността на данните и разделимостта в мрежите обикновено са лоши), а зададеният размер на пресичане е малък по дефиниция. С други думи:този режим е доминиран от хардуерни тесни места.

Какво ще кажете за супервъзлитете все пак?

Тъй като това би било предположение и много се интересувам от мрежови модели, си позволих да внедря драматично опростен мрежов инструмент, базиран на вашия модел на данни, за да направя някои измервания. (Съжалявам, че е на C#, но генерирането на добре структурирани мрежи е достатъчно трудно на езика, който владея най-добре...)

Когато отправям заявка към свръхвъзлите, получавам резултати в диапазона от 7 ms върхове (това е на 12 милиона записа в 1,3 GB db, като най-голямата група има 133 000 елемента в нея и потребител, който следва 143 групи.)

Предположениета в този код е, че броят на групите, следвани от потребител, не е голям, но това изглежда разумно тук. Ако не е, бих избрал подхода с тежко писане.

Чувствайте се свободни да играете с кода. За съжаление ще има нужда от малко оптимизация, ако искате да опитате това с повече от няколко GB данни, защото просто не е оптимизирано и прави някои много неефективни изчисления тук и там (особено бета-претегленото произволно разбъркване може да бъде подобрено ).

С други думи:все още не бих се притеснявал за ефективността на подхода с тежко четене . Проблемът често не е толкова, че броят на потребителите расте, а че потребителите използват системата по неочаквани начини.

Подходът за тежко писане

Алтернативният подход вероятно е да обърнете реда на свързване:

UserItemLinker
{
 userId,
 itemId,
 groupIds[]  // for faster retrieval of the linker. It's unlikely that this grows large
}

Това е може би най-мащабируемият модел на данни, но не бих се съгласил, освен ако не говорим за ОГРОМНИ количества данни, където разделянето е ключово изискване. Ключовата разлика тук е, че вече можем ефективно да разделим данните, като използваме userId като част от ключа на фрагмента. Това помага за паралелизиране на заявките, ефективно разделяне и подобряване на локалността на данните в сценарии с множество центрове за данни.

Това може да се тества с по-сложна версия на тестовото стенд, но все още не намерих време и, честно казано, мисля, че е излишно за повечето приложения.



  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. MongoDB Покажи текущия потребител

  2. MongoDB или CouchDB - годни за производство?

  3. Как да актуализирам документ на Mongo след поставянето му?

  4. Свойството с изтичане на срока на действие на Mongoose не работи правилно

  5. Контролен списък за сигурност за производствени внедрявания на MongoDB