请优化多连接查询

时间:2012-08-23 18:45:54

标签: mysql sql query-optimization average

我对sql进行了查询,但它真的很重,而且我真的不知道如何优化它,解释如下:

SELECT tyds.user_tyd, 
       tyds.product_tyd, 
       tyds.action_tyd, 
       products.price_product, 
       data_8, 
       data_9, 
       avg_8, 
       sum_9 
FROM   tyds 
       INNER JOIN products 
               ON tyds.product_tyd = products.id_product 
       INNER JOIN (SELECT product_tyd, 
                          Avg(data_tyd) AS avg_8 
                   FROM   tyds 
                   WHERE  action_tyd = 8 
                   GROUP  BY product_tyd) Agg_1 
               ON Agg_1.product_tyd = tyds.product_tyd 
       INNER JOIN (SELECT product_tyd, 
                          Sum(data_tyd) AS sum_9 
                   FROM   tyds 
                   WHERE  action_tyd = 9 
                   GROUP  BY product_tyd) Agg_2 
               ON Agg_2.product_tyd = tyds.product_tyd 
       INNER JOIN (SELECT product_tyd, 
                          data_tyd AS data_8 
                   FROM   tyds 
                   WHERE  user_tyd = 3 
                          AND action_tyd = 8) Agg_3 
               ON Agg_3.product_tyd = tyds.product_tyd 
       INNER JOIN (SELECT product_tyd, 
                          data_tyd AS data_9 
                   FROM   tyds 
                   WHERE  user_tyd = 3 
                          AND action_tyd = 9) Agg_4 
               ON Agg_4.product_tyd = tyds.product_tyd 
WHERE  tyds.user_tyd = 3 
       AND tyds.action_tyd = 1 
GROUP  BY tyds.product_tyd 

所有这些联合,因为我需要得到很多东西: 我在tyds.user_tyd = 3中定义了一个id_user tyds.action_tyd = 1因为我想按tyds.product_tyd分组,前面的id_user为tyds.action_tyd = 1。

然后我想要: -data_8是tyds.data_tyd的值WHERE user_tyd = 3 AND action_tyd = 8 -same for data_9

-for AVG和COUNT我想跳过tyds.user_tyd条件,只按id_product分组。

实际上,这个查询正在运行,但我认为它真的很重,并且有太多的SELECT ......

我在一个月前提出了类似的问题,但我不得不审查我的架构,所以我很抱歉......

非常感谢。

e1:我使用MySQL

2 个答案:

答案 0 :(得分:2)

您实际上并不需要所有这些连接和子查询;您可以使用CASE expressionsWHERE - 子句中的逻辑移到字段列表中来消除大部分内容:

SELECT 3 AS user_tyd, tyds.product_tyd, 1 AS action_tyd,
       products.price_product,
       MAX(CASE WHEN user_tyd = 3 AND action_tyd = 8 THEN data_tyd END) data_8,
       MAX(CASE WHEN user_tyd = 3 AND action_tyd = 9 THEN data_tyd END) data_9,
       AVG(CASE WHEN action_tyd = 8 THEN data_tyd END) AS avg_8,
       SUM(CASE WHEN action_tyd = 9 THEN data_tyd END) AS sum_9
  FROM tyds
  JOIN products
    ON tyds.product_tyd = products.id_product
 WHERE tyds.product_tyd IN
         ( SELECT product_tyd
             FROM tyds
            WHERE tyds.user_tyd = 3
              AND tyds.action_tyd = 1
         )
 GROUP
    BY tyds.product_tyd
;

(注意:第三行和第四行中的MAX(...)只是一种强制非空值优先于空值的方法。)

你必须进行测试,看看这实际上是否更快,但我打赌它是。

答案 1 :(得分:1)

简单示例,仅适用于第一个Agg _%

create temporary table Agg_1
(
  product_tyd ...,
  avg_8 ...
)

insert into Agg_1
SELECT product_tyd, AVG(data_tyd) AS avg_8 FROM tyds WHERE action_tyd = 8 
GROUP BY product_ty

SELECT  tyds.user_tyd, tyds.product_tyd, tyds.action_tyd, products.price_product,
data_8, data_9, avg_8, sum_9 
FROM tyds 
INNER JOIN products 
ON tyds.product_tyd = products.id_product 
INNER JOIN Agg_1 ON Agg_1.product_tyd = tyds.product_tyd
...

现在,我看到你正在研究Mysql。我不确定它是否适用于MySql,我不是MySql专家。但是,我确信它适用于oracle和sybase。