1 Востаннє редагувалося VTrim (05.10.2017 20:14:26)

Тема: Діалоги / 2 користувача

Привіт.
Раніше не звертав уваги на подібне, писав як є, а зараз вирішив запитати вашої думки.
Щоб все стало зрозуміло, є подібна "пошта" для користувачів, щось типу:
http://replace.org.ua/pun_pm/inbox/

Потрібно якнайкраще з'єднати двох користувачів в "діалог".
Таблиця users:
id | name
Таблиця dialogs:
id | first_user | second_user

first_user - той хто "додає" діалог, second_user - той, кого додають. Це ID користувачів.
В даному випадку перестановка хто додав і кого додали неважлива.
Допустимо я авторизований з id 1, то..

SELECT
   u.name as username,
   u.id as to_id 
FROM
   users u 
   LEFT JOIN
      dialogs d 
      ON u.id = IF(d.first_user = 1, d.second_user, d.first_user) 
WHERE
   d.first_user = 1 
   OR d.second_user = 1

Тобто на 1 діалог - 1 запис в БД.

Але є ще один варіант, коли той хто створює діалог, робить в БД відразу два записи, типу (мій id 1, а співрозмовника - 2):
Таблиця dialogs:
id | first_user | second_user
1 | 1 | 2
2 | 2 | 1

Такий варіант зпростить сам запит, оскільки я буду робити вибірку тільки по second_user (діалоги зі мною) + не треба буде IF'ів.
Але збільшить кількість записів в таблиці в два рази. 

Що скажете на рахунок кожного?

Подякували: 0xDADA11C7, sensei, 221VOLT, Monolith, ostap34PHP, leofun016

2

Re: Діалоги / 2 користувача

В другому випадку запит такий.

SELECT
   u.name,
   d.first_user 
FROM
   users u 
   LEFT JOIN
      dialogs d 
      ON u.id = d.first_user 
WHERE
   d.second_user = 1

3

Re: Діалоги / 2 користувача

Я не зрозумів цього

Потрібно якнайкраще з'єднати двох користувачів в "діалог".

Наскільки я зрозумів обидва запити виведуть тільки 1 рядок (за умови айдішка юзера унікальна) і він буде виглядати якось так

1 Vova

4

Re: Діалоги / 2 користувача

truesupport написав:

Я не зрозумів цього

Потрібно якнайкраще з'єднати двох користувачів в "діалог".

Наскільки я зрозумів обидва запити виведуть тільки 1 рядок (за умови айдішка юзера унікальна) і він буде виглядати якось так

1 Vova

Ні, він виведе список користувачів, з якими у мене діалог.

5

Re: Діалоги / 2 користувача

Яка практична користь таблиці dialogs? Навіщо вона задумовувалась?

6

Re: Діалоги / 2 користувача

Kniy написав:

Яка практична користь таблиці dialogs? Навіщо вона задумовувалась?

Вивести список користувачів, з якими була розмова та при кліку на кожен, виводити повідомлення і т.д.
Ну звичайна переписка, як в месенджерах.

7

Re: Діалоги / 2 користувача

З мого досвіду записів краще 2. Просто правильно таблиці розробити.
Я, колись було, зробив модуль переписки. Пропоную тобі таку структуру бази даних:

messages - id, theme(varchar), text(text)

inbox - id, message_id, user_id, sender_id, read_status(tinyint), delete_status ... other_statueses

Тобто, якшо я (user_id = 333) напишу тобі (user_id = 666), то створиться 2 записи в таблиці `inbox`. Один

1(message_id)  333 (user_id)   333(sender_id), 0(read_status)  - мій почтовий ящик

і другий

1(message_id)  666 (user_id)  333(sender_id), 0(read_status)   - твій почтовий ящик

Таким чином, я можу редагувати статуси в своєму ящику і ти незалежно.

SELECT * FROM inbox WHERE user_id=333 AND sender_id != user_id AND read = 0;  - мої непрочитані вхідні

Можна пришвидшити роботу твоєю таблицею dialogs і упростити SQL запроси добавивши поле inbox в таблицю inbox, яке б значило, що це вхідний чи вихідний меседж.
Я завжди вибираю шляхи які спрощують SQL вибірку.

Подякували: Monolith1

8

Re: Діалоги / 2 користувача

В мене 1ший спосіб на 40м рекордів працював 7 секунд а другий на 80м 0 секунд

Подякували: VTrim1

9

Re: Діалоги / 2 користувача

Kniy, з таблицею messages й так ніяких питань нема.

10 Востаннє редагувалося VTrim (04.10.2017 06:34:29)

Re: Діалоги / 2 користувача

truesupport написав:

В мене 1ший спосіб на 40м рекордів працював 7 секунд а другий на 80м 0 секунд

40 і 80 це мільйони?

11

Re: Діалоги / 2 користувача

Для second_user можна ще додати index.

CREATE INDEX second_user ON dialogs(second_user);

12

Re: Діалоги / 2 користувача

забув про індекси, здалось і так всі знають

13

Re: Діалоги / 2 користувача

Якщо ви не проти, можу дати поради:

1. якщо у вас поле з id, то воно повинно містити закінчення id. Тобто в таблиці dialogs поля повинні називатись first_user_id та second_user_id.

2. якщо у вас табличка містить лише поля id та name (можливо ще description), то таку таблицю краще позначати префіксом dict_ (від англійського dictionary - словник).

3. якщо у вашій табличці міститься лише мапінг id між різними таблицями, то таку таблицю краще позначати префіксом map_

4. якщо у вашій табличці містяться історичні дані, наприклад, статистика перегляду вашого сайту, то краще її позначати префіксом hist_ (від англійського - history - історія)

Звичайно ж треба працювати з першим варіантом. Спробуйте такий варіант:

[code=sql]-- Спочатку виводите діалоги, де ви запрошували когось.
-- Тобто під first_user - це ви, отже з таблицею users вам треба з'єднуватись по second_user
select
    u.name as second_user_name
from dialogs as d
    join user as u
        on d.second_user = u.id
where d.first_user = 1
    and d.second_user = 2

-- Об'єднує запити (у них обо'язково повинна співпадати кількість полів)
union all

-- Тепер виводите діалоги, де вас запрошували.
-- Тобто під first_user - ваш співрозмовник, отже з таблицею users вам треба з'єднуватись по first_user
select
    u.name as second_user_name
from dialogs as d
    join user as u
        on d.first_user = u.id
where d.first_user = 2
    and d.second_user = 1[/code]

Подякували: Monolith1

14

Re: Діалоги / 2 користувача

Зверніть увагу, що я не використовував left join.

Подякували: Monolith, ostap34PHP2

15

Re: Діалоги / 2 користувача

ktretyak, ви явно вказуєте в запиті id другого користувача (id 2),  коли на вході повинен бути тільки мій id (нехай id 1), а id співрозмовника повинен визначатися автоматично.
Ви мабуть не так зрозуміли завдання.

16

Re: Діалоги / 2 користувача

Тоді запит змінюється на такий:

-- Спочатку виводите діалоги, де ви запрошували когось.
-- Тобто під first_user - це ви, отже з таблицею users вам треба з'єднуватись по second_user
select
    u.name as second_user_name
from dialogs as d
    join user as u
        on d.second_user = u.id
where d.first_user = 1

-- Об'єднує запити (у них обо'язково повинна співпадати кількість полів)
union all

-- Тепер виводите діалоги, де вас запрошували.
-- Тобто під first_user - ваш співрозмовник, отже з таблицею users вам треба з'єднуватись по first_user
select
    u.name as second_user_name
from dialogs as d
    join user as u
        on d.first_user = u.id
where d.second_user = 1
Подякували: VTrim1

17

Re: Діалоги / 2 користувача

Доволі громіздкий, але варіант цікавий. Дякую.

18

Re: Діалоги / 2 користувача

Якщо вмієте дивитись на плани виконання, то гляньте. Важливіше, що він буде працювати швидко, і у вас не буде непотрібних дублів.

19

Re: Діалоги / 2 користувача

ktretyak написав:

Якщо вмієте дивитись на плани виконання, то гляньте. Важливіше, що він буде працювати швидко, і у вас не буде непотрібних дублів.

EXPLAIN ?
Мабуть найочевидніше просто перевірити час виконання при великих обсягах даних.

20

Re: Діалоги / 2 користувача

Якщо ви працюєте з MySQL/MariaDB, то так - я мав на увазі плани виконання через explain.

VTrim написав:

Мабуть найочевидніше просто перевірити час виконання при великих обсягах даних.

Ні, цим способом потрібно користуватись, коли ви глянули на план виконання і побачили, що використовуються саме ті ключі, які ви очікували задіяти. Інколи ви можете виконати запити з однаковою швидкістю, але один із них буде видаватись з кешу вашої СУБД...

Подякували: ping1