MySQL получить друзей структуры друзей и производительность - PullRequest
5 голосов
/ 21 августа 2011

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

Я нашел пару сообщений, связанных с этим, но меня беспокоит производительность:

Структура 1

Многие посты предлагают структуру, в которой у вас есть таблица, в которой каждая строка представляет ссылку дружбы, например:

    CREATE TABLE `friends` (
    `user_id` int(10) unsigned NOT NULL,
    `friend_id` int(10) unsigned NOT NULL,
    )

говоря, что у пользователя '1' есть три друга '2', '3', '4', а у пользователя '2' есть два друга '1', '5'. Ваша таблица друзей будет выглядеть так:

    user_id    |    friend_id
    1          |    2
    1          |    3
    1          |    4
    2          |    1
    2          |    5

запрос друзей друзей: Как выбрать друзей друзей можно посмотреть здесь SQL для поиска друзей И друзей друзей пользователя . Результат запроса для пользователя '1' должен дать (1,2,3,4,5)

Мое беспокойство: средний пользователь fb имеет около 140 друзей. Частых пользователей будет намного больше. Если у меня будет 20 000 пользователей, это будет как минимум в 3 миллиона строк.

Структура 2

Если бы я мог использовать такую ​​структуру:

    CREATE TABLE `friends` (
    `user_id` int(10) unsigned NOT NULL,
    `friend_1` int(10) unsigned NOT NULL,
    `friend_2` int(10) unsigned NOT NULL,
    `friend_3` int(10) unsigned NOT NULL,
    `friend_4` int(10) unsigned NOT NULL,
    ....
    )

Моя таблица будет выглядеть так (на примере сверху):

    user_id  |  friend_1  |  friend_2  |  friend_3  |  ...
    1        |  2         |  3         |  4         |
    2        |  1         |  5         |            |...

Теперь у меня всего 20 000 строк.

запрос друзей друзей: Чтобы выбрать пользователя друзей друзей, которых я пробовал

    Select * FROM friends as a
    WHERE a.user_id 
    IN (
        SELECT * FROM friends AS b
        WHERE b.user_id = '1'
    )

но я получаю ошибку "# 1241 - Операнд должен содержать 1 столбец (столбцы)". Я думаю, что проблема в том, что подвыбор проходит строку, а не столбец?

Вопросы

Надеюсь, вы понимаете мою озабоченность. Я был бы очень рад любому ответу на эти вопросы

1) найти запрос, который возвращает всех друзей друзей для указанного пользователя в структуре 2 ?

2) Какая структура позволяет мне быстрее возвращать друзей друзей? В структуре 2 я думаю, что "join row with column " может быть медленным, если даже здесь возможно использовать соединение. Спасибо за любые предложения. Если бы вы могли подумать о каких-либо других структурах, возможно, воспользовавшись преимуществами сети малого мира, я был бы рад их услышать.

СПАСИБО !!

Ответы [ 4 ]

3 голосов
/ 21 августа 2011

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

Достаточно быстрый запрос для первого подхода:

(
    select friend_id 
    from friends 
    where user_id = 1
) union (
    select distinct ff.friend_id 
    from 
        friends f
        join friends ff on ff.user_id = f.friend_id
    where f.user_id = 1
)

Для достижения максимальной производительности вам необходимо:имеют эти индексы:

ALTER TABLE `friends` ADD UNIQUE INDEX `friends_idx` (`user_id` ASC, `friend_id` ASC);
ALTER TABLE `friends` ADD INDEX `friends_user_id_idx` (`user_id` ASC);
2 голосов
/ 21 августа 2011

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

SELECT friend_id FROM friends WHERE user_id IN (

       SELECT friend_id FROM friends WHERE user_id='$USER_ID'

);

РЕДАКТИРОВАТЬ: Извините, я только что проснулся и понял после публикации ответа, что это совсем не то, что вы искали. Sry.

1 голос
/ 21 августа 2011

Не используйте «Структуру 2», вы не можете создать столбец для всех пользователей, если только у 1 пользователя есть, скажем, 100 друзей (что около 10К друзей или более?), Это приводит к низкой производительности, для структуры 1 вы можете сделатьпростое соединение с одной и той же таблицей:

select u.user_id, f.friend_id 
from friends as u 
  inner join friends as f
    on (u.friend_id=f.friend_id);

РЕДАКТИРОВАТЬ:

ваша ошибка # 1241 означает, что вы используете * в подвыборке, и таблица возвращает более 1 столбца, ваш подзапрос долженвернуть только один столбец (не важно, сколько строк), поэтому замените «*» на «user_id» (без кавычек)

Решение 1 не только быстрее, но и гибче, я не рекомендую подзапросдля простого выбора, подобного этому, просто присоединитесь к той же таблице (это намного быстрее, чем подвыбор).

Решение 2, на мой взгляд, вовсе не решение, оно не гибкое, оно медленнее, оно занимает больше местана HD больше столбцов означает меньшую производительность в MySQL.Как вы можете индексировать такую ​​вещь?И как вы можете выбрать по friend_id, а не по user_id, вы смотрите в каждом столбце для этого friend_id?

0 голосов
/ 19 сентября 2014

Как указано в приведенном ниже ответе, решение 1 предпочтительнее решения 2. Также решение 1 будет работать для приличного количества данных.

Однако, когда дела идут больше, есть и третье решение - Граф Базы данных.

Когда ваша модель данных фокусируется на «отношениях», а не на «объектах», СУБД плохо масштабируютсятак как они должны выполнять поиск по соответствующим таблицам.Индексы БД делают это проще, но этого было недостаточно, поэтому на помощь пришли базы данных графов.

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

Вот некоторая информация для начала:

http://www.slideshare.net/maxdemarzi/graph-database-use-cases

Neo4j или OrientDB являются одними из популярных вариантов.

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