MYSQL-选择两个表之间的唯一公共列-最高效的查询

时间:2019-02-28 17:10:33

标签: mysql sql

我有两个表:

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

上面的通知:

  • ID为2的用户是唯一拥有电话号码222的用户
  • ID为4的用户是唯一拥有电话号码444的用户

我需要通过MySQL查询获得这些结果。

换句话说:在db_contacts中存在该电话号码的情况下,如何选择所有具有唯一电话号码的用户。

我需要我的最终结果是这样的:

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

PS:“电话”列之间没有外键,因为用户可以拥有不在db_contacts中的电话。

在现实生活中,db_contacts包含大约一百万条记录,而user_contacts包含约五百万条记录。

我尝试和失败的事情,并且花费大量时间执行:

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 :(得分:1)

我想你想要

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;

not exists版本可能会更快。

答案 1 :(得分:1)

我将使用带有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)

答案 2 :(得分:1)

首先,我要感谢发布解决方案的所有人,他们都工作了。

但是我对响应时间有些挑剔,其他人提供的解决方案花了很多时间才能执行,几秒钟。

万一有人遇到类似问题,我最后创建了一个新表,称为users_unique_contacts,并在users_contacts上创建了一个触发器AFTER INSERT,以检查新创建的联系人是否在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,执行时间为毫秒。