优化使用多个子选择的SQL查询来显示列

时间:2018-06-05 12:57:22

标签: sql sql-server optimization query-optimization

所以我有以下架构:

enter image description here

我正在尝试以下列格式获取数据:

 ________________________________________
| Id | Property1 | Property2 | Property3 |
_________________________________________
| 123| Value1     | Value2     | Value3  |
 ________________________________________

所以,我编写SQL查询的方式是这样的:

SELECT
Id
,(SELECT pv.Value FROM CampaignProperty AS cp LEFT JOIN PropertyValue AS pv ON cp.Id = pv.CampaignPropertyId WHERE cp.Name = "Property1" AND pv.ContactId = c.Id AND cp.CampaignId = c.ActiveCampaignId) AS "Property1"
,(SELECT pv.Value FROM CampaignProperty AS cp LEFT JOIN PropertyValue AS pv ON cp.Id = pv.CampaignPropertyId WHERE cp.Name = "Property2" AND pv.ContactId = c.Id AND cp.CampaignId = c.ActiveCampaignId) AS "Property2"
,(SELECT pv.Value FROM CampaignProperty AS cp LEFT JOIN PropertyValue AS pv ON cp.Id = pv.CampaignPropertyId WHERE cp.Name = "Property3" AND pv.ContactId = c.Id AND cp.CampaignId = c.ActiveCampaignId) AS "Property3"
FROM Contact c

我遇到的问题是我已经为10多个属性做了这个,我有几个LEFT JOIN和多个过滤器使我的查询难以置信地表现不佳。在SQL Management studio中对此进行分析后,我发现瓶颈在上面显示的SELECT中。

我如何获得相同的结果但性能更好?还有其他方法可以进行查询吗?

重要的是要注意PropertyValue表目前还没有索引......

3 个答案:

答案 0 :(得分:2)

由于多个级别的加入,这有点棘手。我想你想要:

SELECT cp.ContactId,
       MAX(CASE WHEN cp.Name = 'Property1' THEN pv.CampaignProperty END) as Property1,
       MAX(CASE WHEN cp.Name = 'Property2' THEN pv.CampaignProperty END) as Property2,
       MAX(CASE WHEN cp.Name = 'Property3' THEN pv.CampaignProperty END) as Property3
FROM Contact c LEFT JOIN
     CampaignProperty cp
     ON cp.ContactId = c.id AND
        cp.CampaignId = c.ActiveCampaignId LEFT JOIN
     PropertyValue pv
     ON cp.Id = pv.CampaignPropertyId
FROM Contact c
GROUP BY c.Id;

为了提高性能,您需要CampaignProperty(ContactId, CampaignId, Id, Name)PropertyValue(CampaignPropertyId, CampaignProperty)上的索引。

答案 1 :(得分:0)

您可以通过单个SELECT语句执行聚合

select c.id, max(case when cp.Name = 'Property1' then cp.value end) as Property1,
             max(case when cp.Name = 'Property2' then cp.value end) as Property2,
             max(case when cp.Name = 'Property3' then cp.value end) as Property3
from Contact c left join 
     CampaignProperty cp 
     on c.id = cp.ContactId left join
     PropertyValue pl 
     on pl.CampaignPropertyId = cp.id
group by c.id;

答案 2 :(得分:0)

如果你可以使用多行

SELECT c.ID, cp.Name, pv.Value 
  FROM Contact c     
  JOIN CampaignProperty AS cp 
    ON cp.CampaignId = c.ActiveCampaignId  
   AND cp.Name IN ('Property1', 'Property2', 'Property3')       
  LEFT JOIN PropertyValue AS pv 
    ON cp.Id = pv.CampaignPropertyId 
   AND pv.ContactId = c.Id 
 ORDER BY c.ID, cp1.Name