Эффективный дизайн базы данных MySQL для приложения, похожего на Tinder - PullRequest
3 голосов
/ 11 марта 2019

Я создаю приложение, подобное Tinder. Который пользователь может провести вправо или лайк и провести пальцем влево или не любить других пользователей. Проблема в хранении операций пользователей. Таблица необходима для операций пользователей, как показано ниже

Person 1.   |   Person 2.    |     op
__________________________________
000001.          000007.          Dislike
000001.          000011.          Like
000001.          000053.          Dislike
000001.          000173.          Dislike

Хранит операции, а также использует их, чтобы больше не показывать пользователю. Это нормально до сих пор.

Но проблема в том, что если 1000 пользователей проведут пальцем еще 1000 пользователей, в этой таблице будет 1 М строк. И если 100 000 пользователей делают это ... Это идет в 100 миллионов строк! Что очень огромно.

У вас, ребята, есть идея для конструкции, которая не станет такой большой?

Спасибо.

Ответы [ 3 ]

1 голос
/ 15 марта 2019

Есть несколько вещей, которые следует учитывать.

Во-первых, размер таблицы не очень интересен, если вы не знаете, какие типы запросов вам нужно выполнить. Как уже говорили другие, не нужно бояться таблиц с сотнями миллионов строк, и если вы запрашиваете индексируемые поля, вы, вероятно, можете масштабировать до миллиардов строк, не переходя к экзотическим решениям просто покупка большего и лучшего оборудования. Итак, решение, в котором 90% ваших запросов

select * from users where user_id not in (select interacted_user_id from interactions where interacting_user_id = $current_user) limit 10

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

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

Один из способов, которым вы можете разделить свои данные, - это собрать «взаимодействия» по регионам. Это требует некоторых размышлений - вам, вероятно, не нужны «жесткие» границы, а скорее перекрывающиеся географии. Каждое место на карте может иметь несколько перекрывающихся «регионов», каждый со своей таблицей. Чем больше пользователей у вас в регионе, тем меньше у вас перекрывающихся кругов - у Манхэттена может быть 3 региона, у Гренландии может быть только 1. Ваш запрос затем просматривает таблицы для каждого перекрывающегося региона и объединяет пользователей, которые ранее не имели взаимодействовал с текущим пользователем.

1 голос
/ 11 марта 2019

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

С этим столбцом строки не будут складываться, и у вас никогда не будетмиллионы строк.

Также вам не нужно хранить, когда людям нравится вместе.

РЕДАКТИРОВАТЬ: а почему бы не CHECKSUM () с обоими столбцами для хранения хеша для каждого отношения?Это будет легче.

EDIT2: и не забывайте, что это приложение любви.И люди не совпадают со всеми, потому что у них есть сексуальная ориентация.

0 голосов
/ 14 марта 2019

Если человеку 1 не понравился человек 2, нет необходимости показывать человека 1 человеку 2. Даже если вы покажете его, они никогда не совпадут.Поэтому ваши расчеты 1K x 1K = 1M немного завышены.

Однако, если вы все еще хотите иметь наборы лайков / дислайков для обоих пользователей, вы можете рассмотреть эту ужасную идею «сжатия» строк.

Представьте, что у вас есть последовательность, подобная этой:

| Person 1 | Person 2 |  Op       |
| -------- | -------- | --------- |
| 0001     | 1010     |  Dislike  |
| 0001     | 1011     |  Dislike  |
| 0001     | 1012     |  Dislike  |
| 0001     | 1013     |  Dislike  |
| 0001     | 1015     |  Like     |
| 0001     | 1017     |  Dislike  |
| 0001     | 1018     |  Dislike  |
| 0001     | 1019     |  Dislike  |
| 0001     | 1021     |  Like     |

Если у вас есть идентификаторы, следующие друг за другом, вы можете показать их как

| Person 1 | Person 2 |  Op       | N    |
| -------- | -------- | --------- | ---- |
| 0001     | 1010     |  Dislike  | 3    |
| 0001     | 1015     |  Like     | 0    |
| 0001     | 1017     |  Dislike  | 2    |
| 0001     | 1021     |  Like     | 0    |

, где N - максимальный идентификатор в последовательности(напр. 1010 + 3 = 1013).Если вы определите N как неподписанный tinyint, то максимально возможный размер последовательности может составить 255, то есть теоретически 255 последовательных дислайков / лайков можно сохранить как 1 запись.

И запрос будет чем-товот так (представьте, что вы ищете идентификатор 1013):

SELECT a.* 
FROM (
    SELECT *
    FROM `table`
    WHERE person_1 = 0001
      AND person_2 >= (1013 - 255) -- 255 is a max size of a sequense 
      AND person_2 <= 1013
) a
WHERE a.person_2 <= 1013 AND a.person_2 + N >= 1013

Подвыбор ограничит диапазон возможных записей, тогда основной выбор будет соответствовать записи, если она существует.В этом случае это будет

| Person 1 | Person 2 |  Op       | N    |
| -------- | -------- | --------- | ---- |
| 0001     | 1010     |  Dislike  | 3    |

Но лично я бы пошел с этим и предпочел бы ваше текущее решение из-за его простоты.

ИЛИ как другой вариант, вы можете сжатьстол таким образом

| Person 1 | Person 2 | Max Person 2 |  Op       |
| -------- | -------- | ------------ | --------- |
| 0001     | 1010     | 1013         |  Dislike  |
| 0001     | 1015     | 1015         |  Like     |
| 0001     | 1017     | 1019         |  Dislike  |
| 0001     | 1021     | 1021         |  Like     |
...