我可以完成此查询,但需要25秒。太长了!如何优化此查询?
SELECT COUNT(DISTINCT u1.User_ID ) AS total
FROM UserClicks u1
INNER JOIN (SELECT DISTINCT User_ID
FROM UserClicks
WHERE (Date BETWEEN DATE_SUB(:startDate, INTERVAL 1 MONTH) AND :startDate)) u2
ON u1.User_ID = u2.User_ID
WHERE (u1.Date BETWEEN :startDate AND :endDate)
这是在MySQL数据库上使用
答案 0 :(得分:2)
SELECT COUNT(*) AS total
FROM (
SELECT DISTINCT User_ID
FROM UserClicks
WHERE Date BETWEEN DATE_SUB(:startDate, INTERVAL 1 MONTH) AND :startDate
) u1
WHERE EXISTS
(
SELECT NULL
FROM UserClicks u2
WHERE u2.User_ID = u1.User_ID
AND u2.Date BETWEEN :startDate AND :endDate
)
在(User_ID, Date)
上创建综合索引:
CREATE INDEX ix_userclicks_user_date ON UserClicks (User_ID, Date)
如果您的用户很少,但点击次数很多,并且有Users
个表格,那么您可以使用Users
表格代替DISTINCT
:
SELECT COUNT(*)
FROM Users u
WHERE EXISTS
(
SELECT NULL
FROM UserClicks uc1
WHERE uc1.UserId = u.Id
AND uc1.Date BETWEEN DATE_SUB(:startDate, INTERVAL 1 MONTH) AND :startDate
)
AND EXISTS
(
SELECT NULL
FROM UserClicks uc2
WHERE uc2.UserId = u.Id
AND u2.Date BETWEEN :startDate AND :endDate
)
答案 1 :(得分:0)
您是否尝试将语句外的DATE_SUB(:startDate,INTERVAL 1 MONTH)移动到变量中?你有UserClicks.Date索引吗?
答案 2 :(得分:0)
为什么不使用一个select语句而不是运行嵌套的选择对。现在你基本上运行两个查询。试试这个:
SELECT COUNT(DISTINCT UserClicks.User_ID) AS total
FROM UserClicks
WHERE (UserClicks.Date BETWEEN :startDate AND :endDate)
AND (UserClicks.Date BETWEEN DATE_SUB(:startDate, INTERVAL 1 MONTH) AND :startDate)
如果您在日期列上添加索引,可能会有所帮助:
ALTER TABLE `UserClicks` ADD INDEX ( `Date` );
答案 3 :(得分:0)
MySQL在处理子查询时往往忽略索引,因此必须处理每一行。相反,自我加入怎么样?这只是我的头顶,所以它可能不太正确,但它至少应该指向正确的方向。
SELECT COUNT(DISTINCT u1.User_ID) AS total
FROM UserClicks AS u1
JOIN UserClicks AS u2 USING (User_ID)
WHERE u1.Date BETWEEN :startDate AND :endDate
AND u2.Date BETWEEN DATE_SUB(:startDate, INTERVAL 1 MONTH) AND :startDate)