0

我的(简化的)数据库架构: 图片

每个操作都有一组可能产生错误的主机名。每个主机名都从域列表中接受,并且每个域都与一个组织相关联(通过接受阶段)。

我想要一个结果集,如:

+----+--------------------+--------------+----------------+--------------+
| id | organization_count | domain_count | hostname_count | errors_count |
+----+--------------------+--------------+----------------+--------------+
| 79 |                  1 |            1 |              4 |            4 |
| 78 |                  1 |            4 |             16 |         NULL |
| 77 |                  1 |            4 |             16 |           16 |
| 76 |                  1 |            4 |             16 |         NULL |
+----+--------------------+--------------+----------------+--------------+

我的查询是:

SELECT operation.id,
       tally_o.organization_count,
       tally_d.domain_count,
       tally_h.hostname_count,
       tally_h.errors_count
FROM   operation
       LEFT JOIN (SELECT hostname_operation.operation_id,
                         COUNT(*) AS hostname_count,
                         errors.errors_count
                  FROM   hostname_operation
                         LEFT JOIN (SELECT operation_id,
                                           COUNT(*) AS errors_count
                                    FROM   hostname_operation
                                    WHERE  error_id IS NOT NULL
                                    GROUP  BY operation_id) AS errors
                                ON hostname_operation.operation_id =
                                   errors.operation_id
                  GROUP  BY operation_id) AS tally_h
              ON operation.id = tally_h.operation_id
       LEFT JOIN (SELECT hostname_operation.operation_id,
                         COUNT(DISTINCT domain.id) AS domain_count
                  FROM   domain
                         JOIN accepted
                           ON domain.id = accepted.domain_id
                         JOIN hostname
                           ON accepted.id = hostname.accepted_id
                         JOIN hostname_operation
                           ON hostname.id = hostname_operation.hostname_id
                  GROUP  BY hostname_operation.operation_id) AS tally_d
              ON operation.id = tally_d.operation_id
       LEFT JOIN (SELECT hostname_operation.operation_id,
                         COUNT(DISTINCT organization.id) AS organization_count
                  FROM   organization
                         JOIN accepted
                           ON organization.id = accepted.organization_id
                         JOIN hostname
                           ON accepted.id = hostname.accepted_id
                         JOIN hostname_operation
                           ON hostname.id = hostname_operation.hostname_id
                  GROUP  BY hostname_operation.operation_id) AS tally_o
              ON operation.id = tally_o.operation_id
ORDER  BY operation.id DESC
LIMIT  0, 4;

我正在使用 MySQL 5.5。尽管查询速度很快(~0,4s),但问题是EXPLAIN每个...LEFT JOIN (SELECT...数据库的显示都没有使用任何索引。像 mysqltuner 这样的软件也表明我正在做很多没有索引的查询。

如何改进查询?SUM + GROUP BY可能是一种方式?

4

1 回答 1

1

好消息是您的查询可以在没有子查询的情况下重写,只使用 3 个左连接和单个分组依据。

编辑:

select o.id,
  count(distinct a.organization_id) organization_count,
  count(distinct a.domain_id) domain_count,
  count(ho.hostname_id) hostname_count,
  count(ho.error_id) errors_count
from operation o 
  left outer join hostname_operation ho on o.id=ho.operation_id
  left join hostname h on h.id=ho.hostname_id
  left join accepted a on a.id=h.accepted_id
group by o.id
order by o.id

您没有提供有关数据库中索引的信息,因此无法对索引的使用做出结论。我只能建议,如果数据库对所有主键和外键都有适当的索引 - 这足以有效执行上面给出的查询。

于 2013-09-02T09:58:19.537 回答