【问题标题】:Optimizing an SQL query which uses multiple sub selects to display columns优化使用多个子选择来显示列的 SQL 查询
【发布时间】:2018-11-14 23:24:05
【问题描述】:

所以我有以下架构:

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

 ________________________________________
| 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 表目前还没有索引...

【问题讨论】:

  • 您的数据模型中没有名为 CampaignProperty 的列。
  • @GordonLinoff CampaignProperty 是一个表格,PropertyValue 也是。我不确定我明白你的意思。尽管如此,我还是在表格中添加了额外的字段,以便更清楚。
  • 请在所有列名中包含别名
  • @paparazzo 完成! :)
  • 键/值表总是很麻烦。复杂而缓慢的查询,从强制性属性中区分可选的问题,不同的属性类型,属性一致性......如果你用简单的列来代替,那就太容易了。每个联系人/广告系列的属性是否差异很大,以至于有必要选择这种可恶的设计?

标签: sql sql-server optimization query-optimization


【解决方案1】:

你可以通过单个 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;

【讨论】:

  • 您的解决方案与 Gordon 的相同。正如我在上面告诉他的,这需要 3 倍于我的初始查询,基准测试。
  • @JavierGarcíaManzano。 . .看看时间,如果你有适当的索引,这将是一个优势。
  • 是的...问题是我们在PropertyValue 表中没有索引。我想我应该在问题中提及它。
【解决方案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) 上建立索引。

【讨论】:

    【解决方案3】:

    如果你能忍受多行

    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
    

    【讨论】:

      猜你喜欢
      • 2020-10-30
      • 1970-01-01
      • 1970-01-01
      • 2015-09-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多