使用 group by 和条件优化 SQL 查询
Posted
技术标签:
【中文标题】使用 group by 和条件优化 SQL 查询【英文标题】:Optimising SQL query using group by and conditions 【发布时间】:2017-02-03 12:30:25 【问题描述】:我有两个表fiches
和fiches_actions
,fiches_actions
表中的条目是对fiches
表中的条目进行的操作,每个操作都有一个action_id
代表该操作。
这是两个表的架构
问题
对于每个 fiche,获取对其执行的最后一个操作 (action_id),然后获取执行的每个操作的计数。
另一个公式:获取对 fiches 所做的每个最后操作的计数
我通过将最后一个 id 插入到该 fiche fiches_actions
table 中的 fiche max(fiches_actions.id)
来获得对 fiche 所做的最后一个操作
这些文件必须验证一些条件
`fiches`.`created_at` >= '2016-01-01 00:00:00'
AND `fiches`.`created_at` <= '2017-02-01 00:00:00'
AND `fiches`.`status` = 0
AND `fiches`.`agent_id` = '51'
我的解决方案
我确实通过这种方法得到了结果:
首先,我创建了一个视图来获取对它所做的每张照片的操作
CREATE VIEW v_fiches_actions AS
SELECT max(fiches_actions.id) as id,
`fiches_actions.action_id`,
fiches_actions.fiche_id
FROM fiches_actions group by fiche_id;
然后,我从这个视图中选择计数
select v_fiches_actions.action_id, count(*) from v_fiches_actions where fiche_id in
( select `fiches`.`id` from fiches where
`fiches`.`created_at` >= '2016-01-01 00:00:00'
AND `fiches`.`created_at` <= '2017-02-01 00:00:00'
AND `fiches`.`status` = 0
AND `fiches`.`agent_id` = '51'
) group by action_id;
这是我得到的结果:这似乎是正确的
| action_id | count(*)
| 3 | 6
| 7 | 1
我的问题
1- 我的方法是否正确,我得到了正确的结果
2- 有没有办法在单个查询中执行此操作(不使用视图)
【问题讨论】:
一次查询的大致思路..from v_fiches_actions fa JOIN fiches f ON f.id=fa.fiche_id WHERE..
我没有在我的查询中加入,或者我不明白你的评论
【参考方案1】:
您的方法并没有错,但它更冗长并且需要比必要的更多工作。
这是另一种方法:
select fa.action_id, count(*)
from fiches_actions fa join
fiches f
on fa.fiche_id = f.id
where f.created_at >= 2016-01-01' and
f.created_at <= '2017-02-01' and
f.status = 0 and
f.agent_id = 51 and
fa.created_at = (select max(fa2.created_at)
from fiches_actions fa2
where fa2.fiche_id = f.id
)
group by action_id;
为了性能,索引fiches(agent_id, status, created_at, id)
和fiches_actions(fiche_id, created_at)
。
相关的子查询(尤其是正确的索引)应该比聚合快得多。为什么?相关子查询仅在过滤器之后剩余的行上运行。另一方面,聚合必须聚合fiche_actions
表中的所有行。
注意事项:
您不需要查询视图。 对于日期常量,您不需要时间。 表别名使查询更易于编写和阅读。 不要对51
使用单引号,假设id 是一个数字。仅对字符串和日期常量使用单引号。
【讨论】:
是的,这是正确的答案,我在结果中弄错了。谢谢你的笔记:)【参考方案2】:如果 id 是可用于连接表的主键,则无需使用两个选择即可。
你可以在没有第二次选择的情况下完成它:
CREATE VIEW col1, col2, count(*) as new_col
AS SELECT FROM Table1 INNER JOIN OtherTable ON ID = ID
WHERE created_at.table1 BETWEEN 2016-01-01 AND 2017-02-01 AND status.table1 =o AND agent_id.table1 = 51 AND..
【讨论】:
感谢 Raphael 为您解答,但您的回答中没有按action_id
分组,我不想与 views
合作以上是关于使用 group by 和条件优化 SQL 查询的主要内容,如果未能解决你的问题,请参考以下文章
利用 group by 的 Loose Index Scan 优化 sql
优化 SQL:如何重写此查询以提高性能? (使用子查询,摆脱 GROUP BY?)
MySql学习 —— where / having / group by / order by / limit 简单查询