Хранение иерархических данных (MySQL) для реферального маркетинга

Мне нужно иметь иерархию 5 уровней для пользователей, зарегистрированных на веб-сайте. Каждый пользователь приглашен другим, и мне нужно знать всех потомков для пользователя. А также предки для пользователя.

Я имею в виду 2 решение.

  • Сохранение таблицы с отношениями таким образом. Таблица закрытия:

    ancestor_id  descendant_id  distance
    1            1              0
    2            2              0
    3            3              0
    4            4              0
    5            5              0
    6            6              0
    2            3              1
  • Наличие этой таблицы для отношений. Хранение в таблице 5 уровней предков. Таблица "предков":

   user_id ancestor_level1_id ancestor_level2_id ancestor_level3_id ancestor_level4_id ancestor_level5_id
   10      9                  7                  4                  3                  2
   9       7                  4                  3                  2                  1

Являются ли эти хорошие идеи?

Я знаю о "модели списка смежности" и "измененном алгоритме обхода дерева предзаказов", но являются ли эти хорошие решения для "реферальной" системы?

Запросами, которые мне нужно выполнить на этом дереве, являются:

  • часто добавляя новых пользователей
  • Когда пользователь покупает что-то, их источники получают процентную комиссию.
  • каждый пользователь должен иметь возможность узнать, сколько людей они упомянули (и сколько людей было направлено людьми, которых они упомянули....) на каждом уровне.
+2
13 мая '11 в 17:51
источник поделиться
4 ответа

Таблица закрытия

ancestor_id  descendant_id  distance
    1            1              0
    2            2              0
    3            3              0
    4            4              0
    5            5              0
    6            6              0
    2            3              1

Чтобы добавить пользователя 10, упомянутого пользователем 3. (я не думаю, что вам нужно заблокировать таблицу между этими двумя вставками):

insert into ancestor_table
select ancestor_id, 10, distance+1
from ancestor_table
where descendant_id=3;

insert into ancestor_table values (10,10,0);

Чтобы найти всех пользователей, упомянутых пользователем 3.

select descendant_id from ancestor_table where ancestor_id=3;

Чтобы подсчитать этих пользователей по глубине:

select distance, count(*) from ancestor_table where ancestor_id=3 group by distance;

Чтобы найти предков пользователя 10.

select ancestor_id, distance from ancestor_table where descendant_id=10;

Недостатком этого метода является количество пространства для хранения, которое займет эта таблица.

+5
16 мая '11 в 19:21
источник

Используйте механизм хранения OQGRAPH.

Вероятно, вы хотите отслеживать произвольное количество уровней, а не только 5 уровней. Возьмите одну из вилок MySQL, которая поддерживает движок QGRAPH (например, MariaDB или OurDelta) и используйте это для хранения вашего дерева. Он реализует модель списка смежности, но, используя специальный столбец с именем latch, чтобы отправить команду движку хранилища, указав, какой запрос выполнить, вы получаете все преимущества таблицы закрытия, не требуя бухгалтерская работа каждый раз, когда кто-то регистрируется для вашего сайта.

Вот запросы, которые вы будете использовать в OQGRAPH. См. Документацию по адресу http://openquery.com/graph-computation-engine-documentation

Мы будем использовать исходный текст в качестве реферера и в качестве реферирования укажем.

Чтобы добавить пользователя 11, упомянутого пользователем 10

insert into ancestors_table (origid,destid) values (10,11)

Чтобы найти всех пользователей, упомянутых пользователем 3.

SELECT linkid FROM ancestors_table WHERE latch = 2 AND origid = 3;

Чтобы найти предков пользователя 10.

SELECT linkid FROM ancestors_table WHERE latch = 2 AND destid = 10;

Чтобы найти количество пользователей на каждом уровне, указанное пользователем 3:

SELECT count(linkid), weight
FROM ancestors_table
WHERE latch = 2 AND origid = 3
GROUP BY weight;
+3
15 мая '11 в 21:32
источник

Управление иерархическими данными в MySQL

В общем, мне нравится "вложенный набор", особенно. в MySQL, который не имеет языковой поддержки для иерархических данных. Это быстро, но вам нужно убедиться, что ваши разработчики читают эту статью, если простота обслуживания - это большое дело. Он очень гибкий, что, по-видимому, не имеет большого значения в вашем случае.

Кажется, это хорошо подходит для вашей проблемы - в реферальной модели вам нужно найти дерево рефереров, которое быстро входит в модель вложенного набора; вам также нужно знать, кто является ~ детьми @данного пользователя и глубиной их отношений; это тоже быстро.

+1
15 мая '11 в 19:41
источник

Ограниченная строка предков

Если вы серьезно рассматриваете 5-уровневую таблицу отношений, это может упростить работу с использованием разделительной строки предков вместо 5 отдельных столбцов.

user_id  depth   ancestors
10       7       9,7,4,3,2,1
9        6       7,4,3,2,1
...
2        2       1
1        1       (empty string)

Вот некоторые команды SQL, которые вы будете использовать с этой моделью:

Чтобы добавить пользователя 11, упомянутого пользователем 10

insert into ancestors_table (user_id, depth, ancestors)
select 11, depth+1, concat(10,',',ancestors)
from ancestors_table
where user_id=10;

Чтобы найти всех пользователей, упомянутых пользователем 3. (Обратите внимание, что этот запрос не может использовать индекс.)

select user_id
from ancestors_table
where ancestors like '%,3,%' or ancestors like '3,%' or ancestors like '%,3';

Чтобы найти предков пользователя 10. Вам нужно разбить строку в вашей клиентской программе. В Ruby код будет ancestorscolumn.split(",").map{|x| x.to_i}. Там нет хорошего способа разбить строку в SQL.

select ancestors from ancestors_table where user_id=10;

Чтобы найти количество пользователей на каждом уровне, указанное пользователем 3:

select
   depth-(select depth from ancestors_table where user_id=3),
   count(*)
from ancestors_table
where ancestors like '%,3,%' or ancestors like '3,%' or ancestors like '%,3'
group by depth;

Вы можете избежать атак SQL-инъекций в частях like '%,3,%' этих запросов с помощью like concat('%,', ?, ',%') и привязать целое число для номера пользователя к заполнителю.

+1
16 мая '11 в 17:14
источник

Посмотрите другие вопросы по меткам или Задайте вопрос