我管理一个房地产网站。我有一个包含禁止用户的表(小表)和一个名为 advert_views 的表,该表跟踪每个用户查看的每个列表(目前有 130 万行,并且还在不断增长)。 advert_views 表还记录了查看的每个广告的 IP 地址。
我想获取被禁止用户使用的IP地址,并检查这些被禁止用户是否开设了新帐户。我运行了以下查询:
SELECT adviews.user_id AS 'banned user_id',
adviews.client_ip AS 'IPs used by banned users',
adviews2.user_id AS 'banned users that opened a new account'
FROM banned_users
LEFT JOIN users on users.email_address = banned_users.email_address #since I don't store the user_id in banned_users
LEFT JOIN advert_views adviews ON adviews.user_id = users.id AND adviews.user_id IS NOT NULL # users may view listings when not logged in but they have restricted access to the information on the listing
LEFT JOIN (SELECT client_ip,
user_id
FROM advert_views
WHERE user_id IS NOT NULL
) adviews2
ON adviews2.client_ip = adviews.client_ip
WHERE banned_users.rec_status = 1 and adviews.user_id <> adviews2.user_id
GROUP BY adviews2.user_id
我在 advert_views 表和 users 表上应用了索引,如下所示:
我的查询需要半个小时才能执行。有没有办法提高查询速度?
谢谢! 克里斯
最佳答案
首先:为什么要对表进行外部连接?或者更好:为什么您尝试外部连接表?左连接意味着即使没有匹配项也可以从表中获取数据。但是,您的结果可能包含所有值为空的行。 (但这不会发生,因为 where 子句中的 adviews.user_id <> adviews2.user_id
会忽略所有外部连接的行。)不要让 DBMS 做不必要的工作。如果您想要内部联接,那么就不要外部联接。 (尽管执行时间的差异不会很大。)
下一步:您从banned_users中进行选择,但仅用它来检查是否存在。你不应该这样做。使用EXISTS
或IN
条款代替。 (这主要是为了可读性,并且为了不产生重复的结果。这可能不会加快速度。)
SELECT av1.user_id AS 'banned user_id',
av2.client_ip AS 'IPs used by banned users',
av2.user_id AS 'banned users that opened a new account'
FROM adviews av1
JOIN adviews av2 ON av2.client_ip = av1.client_ip AND av2.user_id <> av1.user_id
WHERE av1.user_id IN
(
SELECT user_id
FROM users
WHERE email_address IN (select email_address from banned_users where rec_status = 1)
)
GROUP BY av2.user_id;
您可以更换内部IN
带有连接的子句。这主要是个人喜好的问题,但也是过去MySQL有时在IN
上表现不佳的原因。条款,所以很多人都养成了加入的习惯。
WHERE av1.user_id IN
(
SELECT u.user_id
FROM users u
JOIN banned_users bu ON bu.email_address = u.email_address
WHERE bu.rec_status = 1
)
最后考虑删除 GROUP BY
条款。它将每次重用 user_id 将结果减少到一行,显示其相关的被禁止 user_id 之一(任意选择,以防有多个 user_id)。我不知道你的 table 。每次重用 user_id 是否会获得很多记录?如果没有,请删除该子句。
对于索引我建议:
- banned_users(rec_status、电子邮件地址)
- 用户(电子邮件地址、用户 ID)
- 广告浏览量(user_id、client_ip)
- 广告浏览(client_ip、user_id)
关于mysql - 使用mysql查询大表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39677217/