我正在使用MySQL
我无法改变数据库结构,所以这不是一个可悲的选择
问题:
当我使用带有CASE的GROUP BY时(根据我的情况需要),MYSQL使用 file_sort和延迟很大(大约2-3分钟):
但是当我不使用CASE只是GROUP BY group_id时,MYSQL很容易使用 索引和结果很快:
Scenerio:详细
表 msgs ,包含已发送邮件的记录,包含字段:
ID
user_id,(发送消息的人)
类型,(0 =>表示它的组msg。在此下发送的所有消息都由group_id标记。所以假设group_id = 5发送5个消息,该表将有5个记录,group_id = 5和type = 0。对于类型> 0,group_id将为NULL,因为所有其他类型都没有group_id,因为它们是发送给单个收件人的单个消息)
group_id(如果type = 0,将包含group_id,否则为NULL)
表包含大约1000万条用户ID 50001和不同类型的记录(即组和个别消息)
现在QUERY:
SELECT
msgs.*
FROM
msgs
INNER JOIN accounts
ON (
msgs.user_id = accounts.id
)
WHERE 1
AND msgs.user_id IN (50111)
AND msgs.type IN (0, 1, 5, 7)
GROUP BY CASE `msgs`.`type` WHEN 0 THEN `msgs`.`group_id` ELSE `msgs`.`id` END
ORDER BY `msgs`.`group_id` DESC
LIMIT 100
我已在一个QUERY中获取摘要
所以发送到群组的消息让我们说5(此表中有5条记录)将显示为摘要的1条记录(我可能会稍后显示COUNT,但这不是问题)。
各个msgs的NULL为group_id,所以我不能把'GROUP BY group_id'coz用于将所有单个msgs分组为单个记录,这是不可接受的。
示例输出可以是:
id owner_id, type group_id COUNT
1 50001 0 2 5
1 50001 1 NULL 1
1 50001 4 NULL 1
1 50001 0 7 5
1 50001 5 NULL 1
1 50001 5 NULL 1
1 50001 5 NULL 1
1 50001 0 10 5
现在问题是使用CASE之后的GROUP条件(我目前认为我必须因为我只需要按group_id进行分组,如果type = 0)导致很多延迟因为它没有使用它所做的索引我不使用CASE(就像group_id一样)。请查看上面的SQLFiddles以查看解释结果
任何人都可以提出如何优化的建议
更新
我尝试了一种解决方法,确实可行(将INITIAL查询丢弃到1秒)。使用union,它的作用是最小化结果集,强制SQL在磁盘上为filesort写入(由于结果集很大),限制组msgs的结果集,以及单个msgs(查看下面的查询)
- union的第一部分检索组msgs(类型为0,需要按group_id分组)。应用限制以吸引失控结果集
- 第二个查询检索单个消息,(类型为!= 0的消息,按msgs.id分组 - 不是必需的,只是为了从连接中重复输入保存)。应用限制以吸引失控结果集
- 连接两者以检索所需的结果集
以下是查询:
SELECT
*
FROM
(
(
SELECT
msgs.id as reference_id, user_id, type, group_id
FROM
msgs
INNER JOIN accounts
ON (msgs.user_id = accounts.id)
WHERE 1
AND accounts.id IN (50111 ) AND type = 0
GROUP BY msgs.group_id
ORDER BY msgs.id DESC
LIMIT 40
)
UNION
ALL
(
SELECT
msgs.id as reference_id, user_id, type, group_id
FROM
msgs
INNER JOIN accounts
ON (
msgs.user_id = accounts.id
)
WHERE 1
AND msgs.type != 0
AND accounts.id IN (50111)
GROUP BY msgs.id
ORDER BY msgs.id
LIMIT 40
)
) AS temp
ORDER BY reference_id
LIMIT 20,20
但是有很多警告,
- 我也需要处理内部查询的限制。让我们说每页20rec,并且我在第4页。对于内部查询,我需要应用限制0,80,因为我不确定这两个部分中的哪一个在前3页中有多少记录。因此,随着每页记录和页数的增长,我的查询变得越来越重。让我们说每页1k rec,而在第100页或者1K,负载越来越重,时间呈指数增长
-Cant使用calc_found_rows,因此需要单独使用查询进行计数
主要问题是第一个问题。分页越高,越重,
答案 0 :(得分:0)
这会跑得更快吗?
SELECT id, user_id, type, group_id
FROM
( SELECT id, user_id, type, group_id, IFNULL(group_id, id) AS foo
FROM msgs
WHERE user_id IN (50111)
AND type IN (0, 1, 5, 7)
)
GROUP BY foo
ORDER BY `group_id` DESC
LIMIT 100
需要INDEX(user_id, type)
。
这是否能够正确地提供正确的'回答?
SELECT DISTINCT *
FROM msgs
WHERE user_id IN (50111)
AND type IN (0, 1, 5, 7)
GROUP BY IFNULL(group_id, id)
ORDER BY `group_id` DESC
LIMIT 100
(它需要相同的索引)