优化复杂的SQL查询 - 避免经常运行子查询

时间:2015-11-18 10:25:12

标签: mysql optimization

我写了一个非常低效的查询,我拼命想要从中获得最佳性能。 (我的MySQL技能不是很好,所以请在阅读时放纵......)

首先:我只对数据库进行只读访问。所以不幸的是,我无法创建临时表(我认为这是一个很好的解决方案)。

我的查询的目标是列出每篇文章(表格),同时将过去三年的销售数量列为右侧的单独列。 所有dokument标题都列在“dok”中,所有行项目都列在“pos”中。

这些是表格结构(仅提及相关字段):

技术: ID;重量;价格; ...

DOK: ID;日期; ...

POS: ID; dok_id; art_id;数量; ...

为简单起见,所有表名都被更改,真实表和字段的名称非常复杂。

我的第一次尝试就是这个(三个次级):

select art.id,
art.weight,
art.price,
(select sum(pos.qty) from pos inner join dok on pos.dok_id = dok.id where year(dok.date) = 2013 and pos.art_id = art.id),
(select sum(pos.qty) from pos inner join dok on pos.dok_id = dok.id where year(dok.date) = 2014 and pos.art_id = art.id),
(select sum(pos.qty) from pos inner join dok on pos.dok_id = dok.id where year(dok.date) = 2015 and pos.art_id = art.id)

from art;

效率非常低。

所以我写了一个查询,给我以下结果集(不包括每篇文章,因为并非所有文章都已售出):

art.id,year,qty

使用它作为左表加入它的表:

select art.id,
art.weight,
art.price,
t1.qty,
t2.qty,
t3.qty

from (art)

left join (select art.id, year(dok.date) as yr, sum(pos.qty) as qty from pos inner join dok on pos.dok_id = dok.id inner join art on pos.art_id = art.id where year(dok.date) in >= 2013 group by art.id, year(dok.date)) t1 on t1.id = art.id
left join (select art.id, year(dok.date) as yr, sum(pos.qty) as qty from pos inner join dok on pos.dok_id = dok.id inner join art on pos.art_id = art.id where year(dok.date) in >= 2013 group by art.id, year(dok.date)) t2 on t2.id = art.id
left join (select art.id, year(dok.date) as yr, sum(pos.qty) as qty from pos inner join dok on pos.dok_id = dok.id inner join art on pos.art_id = art.id where year(dok.date) in >= 2013 group by art.id, year(dok.date)) t3 on t3.id = art.id

where t1.yr= 2013 and t2.yr= 2014 and t3.yr= 2015;

此查询仅持续了第一个查询的约50%。那更好,但不如我认为它可以使用你们中的一些想法。 使用子查询作为表格的表现更好,但我认为它仍然会做三次。

有没有办法让MySQL只进行一次子查询,将它用于所有三个连接? 或者有一种完全不同的方式吗?

我期待着你的想法。

来自德国的问候,

的Stefan

1 个答案:

答案 0 :(得分:0)

您可以使用单个子查询,使用SUM中的IF仅将该字段中的值与特定年份的行相加。像这样(未经测试): -

SELECT art.id,
    art.weight,
    art.price,
    t1.qty_2013,
    t1.qty_2014,
    t1.qty_2015
FROM (art)
LEFT JOIN 
(
    SELECT art.id, 
            SUM(IF(year(dok.date) = 2013, pos.qty, 0)) AS qty_2013
            SUM(IF(year(dok.date) = 2014, pos.qty, 0)) AS qty_2014
            SUM(IF(year(dok.date) = 2015, pos.qty, 0)) AS qty_2015
    FROM pos 
    INNER JOIN dok ON pos.dok_id = dok.id 
    INNER JOIN art ON pos.art_id = art.id 
    WHERE YEAR(dok.date) IN (2013, 2014, 2015)
    GROUP BY art.id
) t1 ON t1.id = art.id