使用分组依据和条件优化 SQL 查询

Optimising SQL query using group by and conditions

我有两个 tables fichesfiches_actionsfiches_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..