mysql - 单个子查询很快。添加 1 个子查询很快。但是,将超过 1 个子查询一起添加会使 MySQL 崩溃。怎么修?
问题描述
我有以下查询来选择过去 4 周内每周至少发布一次的用户:
SELECT DISTINCT(user_id) FROM `posts` WHERE
user_id IN (SELECT DISTINCT(user_id) FROM `posts` WHERE post_date > ((UNIX_TIMESTAMP()- (604800*0) ) - 604800) AND post_date <= (UNIX_TIMESTAMP()- (604800*0))) AND
user_id IN (SELECT DISTINCT(user_id) FROM `posts` WHERE post_date > ((UNIX_TIMESTAMP()- (604800*1) ) - 604800) AND post_date <= (UNIX_TIMESTAMP()- (604800*1))) AND
user_id IN (SELECT DISTINCT(user_id) FROM `posts` WHERE post_date > ((UNIX_TIMESTAMP()- (604800*2) ) - 604800) AND post_date <= (UNIX_TIMESTAMP()- (604800*2))) AND
user_id IN (SELECT DISTINCT(user_id) FROM `posts` WHERE post_date > ((UNIX_TIMESTAMP()- (604800*3) ) - 604800) AND post_date <= (UNIX_TIMESTAMP()- (604800*3)))
如果我只使用这 4 个子查询中的任何一个来运行查询,它会很快。
如果我单独运行这 4 个子查询中的任何一个,它们都很快。
但是,当我将这些子查询中的一个以上添加在一起时,MySQL 就会挂起。
我该如何解决这个问题,以便考虑到各个部分的速度很快?
(我应该补充一点,在这种特殊情况下,我不能再添加任何索引,所以解决方案不应该涉及索引)。
解决方案
试试看EXPLAIN <query>
执行计划,每个子查询可以读取很多行数据。
但我建议为此特定目的重新编写查询,它需要GROUP BY
用户和COUNT DISTINCT
周为 4,读取表一次就足够了。
SELECT user_id
FROM `posts`
WHERE post_date > ((UNIX_TIMESTAMP()- (604800*3) ) - 604800)
GROUP BY user_id
HAVING COUNT(DISTINCT
(CASE WHEN post_date > ((UNIX_TIMESTAMP()- (604800*0) ) - 604800) AND post_date <= (UNIX_TIMESTAMP()- (604800*0)) THEN 1
WHEN post_date > ((UNIX_TIMESTAMP()- (604800*1) ) - 604800) AND post_date <= (UNIX_TIMESTAMP()- (604800*1)) THEN 2
WHEN post_date > ((UNIX_TIMESTAMP()- (604800*2) ) - 604800) AND post_date <= (UNIX_TIMESTAMP()- (604800*2)) THEN 3
ELSE 4 END)) = 4
关于查询
WHERE post_date > ((UNIX_TIMESTAMP()- (604800*3) ) - 604800)
仅过滤适用数据CASE WHEN post_date > ((UNIX_TIMESTAMP ...
将其post_date
转换为第 1、2、3 或 4 周
现在如果有如下数据
+---------+------+
| user_id | week |
+---------+------+
| 1 | 1 |
| 1 | 2 |
| 1 | 3 |
| 1 | 3 |
| 2 | 1 |
| 2 | 2 |
| 2 | 3 |
| 2 | 4 |
+---------+------+
每个有四行user_id
,但用户 1 出现在第 1、2、3 周,COUNT DISTINCT week
为 3,用户 2 将计为 4
推荐阅读
- javascript - 为什么 combineLatest 在这种情况下运行但 forkJoin 失败
- vue.js - Vue js 2.6:组件将一个插槽 vnodes 作为道具传递给另一个插槽以进行渲染 | 将数据从一个插槽传输到另一个插槽的组件
- reactjs - 使用命令“npx create-react-app ./client”创建 React 应用程序时出错
- c# - Xamarin 将参数从后面的代码传递到不同的 xaml
- bash - bash' 内置声明 -nz 对 z 参数有什么作用?
- javascript - 为什么不能用 document.forms 选择标签?
- wso2 - wso2 api manager schannel: next InitializeSecurityContext failed-证书链是由不受信任的权威机构颁发的
- xml - visual studio 2019 xslt 调试启用文档功能
- python - 如何在 matplotlib 中使用 Nimbus Roman 字体?
- python - 访问谷歌存储桶的问题