MYSQL - выбор уникальных общих столбцов между двумя таблицами - наиболее эффективный запрос - PullRequest
0 голосов
/ 28 февраля 2019

У меня есть две таблицы:

db_contacts

Phone | Name | Last_Name
--------------------
111   | Foo  | Foo
222   | Bar  | Bar
333   | John | Smith
444   | Tomy | Smith

users_contacts

User_ID | Phone
--------------------
1       | 123
1       | 111
2       | 222
2       | 333
3       | 111
3       | 333
4       | 444

УведомлениеИсходя из вышесказанного:

  • Пользователь с идентификатором 2 - единственный пользователь с номером телефона 222
  • Пользователь с идентификатором 4 - единственный, имеющий номер телефона 444.

Мне нужно получить эти результаты с помощью запроса MySQL.

Другими словами: как выбрать всех пользователей, имеющих уникальный номер телефона, при условии, что этот номер существует вthe db_contacts.

Мне нужно, чтобы мой конечный результат был примерно таким:

User_ID | Phone | Name | Last_Name
------------------------------------
2       | 222   | Bar  | Bar
4       | 444   | Tomy | Smith

PS: между столбцами телефона нет внешнего ключа, поскольку пользователь может иметьтелефон, которого нет в db_contacts.

В реальной жизни db_contacts содержит около 1 миллиона записей, а users_contacts около 5 миллионов записей.

То, что я попробовал, не получилось и взялмного времени для выполнения:

SELECT * 
FROM users_contacts 
WHERE users_contacts.phone IN (
    SELECT users_contacts.phone 
    FROM `users_contacts`
    JOIN db_contacts ON db_contacts.phone = users_contacts.phone
    GROUP BY users_contacts.phone
    HAVING COUNT(users_contacts.phone) = 1
)

Обновление:

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

Ответы [ 3 ]

0 голосов
/ 28 февраля 2019

Я бы использовал простой JOIN с условием NOT EXISTS.Обычно это самый эффективный способ проверить, что что-то не имеет дубликатов;по сравнению с вашим решением это позволяет избежать агрегирования.

SELECT uc.User_ID, dc.*
FROM users_contacts uc
INNER JOIN db_contacts dc ON uc.Phone = dc.Phone
WHERE NOT EXISTS (
    SELECT 1 
    FROM users_contacts uc1 
    WHERE uc1.Phone = dc.Phone AND uc1.User_ID != uc2.User_ID
)

Подсказка: рассмотрите возможность установки следующих индексов:

  • users_contacts(Phone, User_ID)
  • db_contacts(Phone)
0 голосов
/ 01 марта 2019

Сначала я хотел бы поблагодарить всех, кто опубликовал решения, все они работали.

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

В случае, если у кого-то возникла подобная проблема, я создал новую таблицу с именем users_unique_contacts и создал триггер AFTER INSERT для users_contacts, который проверяет, существует ли недавно созданный контакт в users_unique_contacts, еслиего не существует, добавьте его, иначе удалите, поскольку это означает, что номер больше не является уникальным.

Мой триггер работал так:

BEGIN
    IF EXISTS (SELECT 1 = 1 FROM users_unique_contacts WHERE phone = new.phone LIMIT 1) THEN
        BEGIN
                DELETE FROM users_unique_contacts WHERE phone = new.phone LIMIT 1;
        END;
    ELSE
        BEGIN
                INSERT INTO users_unique_contacts (user_id,phone) VALUES (new.user_id, new.phone);
        END;
    END IF;
END

Теперь каждый раз, когда я хочу уникальные номерапользователя, я запрашиваю users_unique_contacts и время выполнения составляет миллисекунды.

0 голосов
/ 28 февраля 2019

Я думаю, что вы хотите:

select uc.*
from user_contacts uc
where not exists (select 1
                  from user_contacts uc2
                  where uc2.phone = uc.phone and uc2.user_id <> uc.user_id
                 );

Для производительности вам нужен индекс для user_contacts(phone, user_id).

Другой метод:

select max(user_id) as user_id, phone
from user_contacts
group by phone
having count(*) = 1;

The not exists версия, вероятно, будет быстрее.

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