我管理一个物业网站。我有一个禁止用户的表(小表)和一个名为advert_views的表,它跟踪每个用户查看的每个列表(当前1.3米行和增长)。 advert_views表alsio记录了所查看的每个广告的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表上应用了索引,如下所示:
我的查询需要半个小时才能执行。有没有办法提高我的查询速度?
谢谢! 克里斯
答案 0 :(得分:0)
首先:你为什么要加入表?或者更好:为什么尝试外连接表?左连接意味着即使没有匹配也能从表中获取数据。但是,您的结果可能包含所有值为null的行。 (但这不会发生,因为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会获得多条记录吗?如果没有,请删除该条款。
至于我建议的指数: