使用分组依据和条件优化 SQL 查询
Optimising SQL query using group by and conditions
我有两个 tables fiches
和 fiches_actions
,fiches_actions
table 中的条目是对 [=15= 中的条目所做的操作] table,每个动作都有一个action_id
代表动作。
这是两个table
的架构
问题
对于每张图片,获取对其执行的最后一个操作 (action_id),然后获取每个操作的计数。
另一个公式:获取对 fiches 进行的每个最后操作的计数
我通过在 fiches_actions
table 中插入最后一个 id 来获取对该胶片所做的最后操作 max(fiches_actions.id)
这些图片必须验证一些条件
`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从这个视图中计数
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- 有没有办法在单个查询中执行此操作(不使用视图)
你的方法并没有错,但它更冗长,需要做更多的工作。
这是另一种方法:
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
table.
中的 all 行
备注:
- 查询不需要视图。
- 对于日期常量,您不需要时间。
- Table 别名使查询更易于编写和阅读。
- 不要对
51
使用单引号,假设 id 是一个数字。仅对字符串和日期常量使用单引号。
如果 id 是可用于连接表的主键,则无需使用两个 selects 即可实现。
一秒钟也能搞定select:
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..
我有两个 tables fiches
和 fiches_actions
,fiches_actions
table 中的条目是对 [=15= 中的条目所做的操作] table,每个动作都有一个action_id
代表动作。
这是两个table
的架构问题
对于每张图片,获取对其执行的最后一个操作 (action_id),然后获取每个操作的计数。
另一个公式:获取对 fiches 进行的每个最后操作的计数
我通过在 fiches_actions
table 中插入最后一个 id 来获取对该胶片所做的最后操作 max(fiches_actions.id)
这些图片必须验证一些条件
`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从这个视图中计数
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- 有没有办法在单个查询中执行此操作(不使用视图)
你的方法并没有错,但它更冗长,需要做更多的工作。
这是另一种方法:
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
table.
备注:
- 查询不需要视图。
- 对于日期常量,您不需要时间。
- Table 别名使查询更易于编写和阅读。
- 不要对
51
使用单引号,假设 id 是一个数字。仅对字符串和日期常量使用单引号。
如果 id 是可用于连接表的主键,则无需使用两个 selects 即可实现。
一秒钟也能搞定select:
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..