SQL Server

时间:2016-11-11 19:37:03

标签: sql-server tsql join subquery query-performance

采用以下两个模拟表:

  

dbo.animal

id  name
1   dog
2   cat
  

dbo.animal_food

id  animal_id  food_id  active
1   1          4        1
2   1          5        1

我需要根据不同的排序结果查询animal多个animal_food子查询。像这样:

 select name, 
        (   select top 1 food_id 
              from animal_food 
             where animal_id = animal.id 
             order by food_id desc) as max_food_id,
        (   select top 1 food_id 
              from animal_food 
             where animal_id = animal.id 
               and active = 1
             order by food_id desc) as max_active_food_id,
  from animal

这显然效率很低 - 我需要加快速度。但是,我无法弄清楚如何将其重构为可以提高性能的连接。

4 个答案:

答案 0 :(得分:1)

如果您只想要指定的两个food_id值,则可以将joingroup by以及所谓的条件聚合一起使用,如下所示:

select 
    name, 
    max(animal_food.food_id) as max_food_id,
    max(case when animal_food.active = 1 then animal_food.food_id else null end) as max_active_food_id,
from animal
inner join animal_food on animal.animal_id = animal_food.animal_id
group by animal.animal_id, animal.name

答案 1 :(得分:1)

这看起来像一个简单的聚合查询,唯一的变化是第三列只考虑request.setAttribute food_id的最大值active = 1。如果是这种情况,这将完成没有子查询的工作:

SELECT
  name,
  MAX(food_id) AS max_food_id,
  MAX(CASE WHEN active = 1 THEN food_id END) AS max_active_food_id
FROM animal
JOIN animal_food = animal.id = animal_food.id
GROUP BY name

如果MAX(CASE WHEN active = 1 THEN food_id END)不等于1,NULL将返回active,而MAX等聚合会忽略空值。

答案 2 :(得分:1)

您还可以使用交叉应用功能并检查哪种方式表现更好

 select name, 
        max_food_id.food_id AS max_food_id,
        max_active_food_id.food_id AS max_active_food_id,
  from animal
  cross apply (
   select top 1 food_id 
              from animal_food 
             where animal_id = animal.id 
             order by food_id desc
) AS max_food_id
cross apply
(   select top 1 food_id 
              from animal_food 
             where animal_id = animal.id 
               and active = 1
             order by food_id desc) as max_active_food_id

答案 3 :(得分:0)

我不确定性能,但这里是使用连接和聚合的查询。这是你正在寻找的还是你已经尝试过这个?

select animal.name
    , max(animal_food_all.food_id) as max_food_id
    , max(animal_food_active.food_id) as max_active_food_id
from animal
    left outer join animal_food as animal_food_all on animal.id = animal_food_all.animal_id
    left outer join animal_food as animal_food_active on animal.id = animal_food_active.animal_id and animal_food_active.active = 1
GROUP BY animal.name

我使用了外连接,以防有动物没有列出食物,如果你想要省略那些你可以改变它的内连接,但无论哪种方式,它可能对性能影响很小(如果有的话)。