【问题标题】:Count Queries slow down with increased number of records计数查询随着记录数量的增加而减慢
【发布时间】:2019-10-22 15:33:28
【问题描述】:

我有以下表格结构:

tb_学生

CustomerId  StudentId  StudentName
 1             1        Michael
 1             2        Sam
 2             1        Declan

tb_Contact_Detail

StudentId ContactId CustomerId ContactName Relation
  1          1         1         Rory      Father
  1          2         1         Rachel    Mother

tb_Channel

ChannelId  ChannelName
   1        Emergency
   2        GeneralInfo

tb_Contact_Channel_Mapping

CustomerId ChannelId StudentId ContactId
   1         1         1          2
   1         2         1          2
   1         2         1          1

tb_Contact_Fields

CustomerId ContactId ContactType(Phone/SMS/Email)
   1         1          Phone
   1         1          Email
   1         1          SMS
   1         2          Email
   1         2          SMS


SELECT @EmailCnt = ISNULL(SUM(CASE WHEN field.FieldType = 'Email' THEN 1 ELSE 0 END), 0),
       @PhoneCnt = ISNULL(SUM(CASE WHEN field.FieldType = 'Phone' THEN 1 ELSE 0 END), 0),
       @SMSCnt = ISNULL(SUM(CASE WHEN field.FieldType = 'SMS' THEN 1 ELSE 0 END), 0)
FROM tb_Students stu WITH (NOLOCK)
     INNER JOIN tb_Contact_Detail det WITH (NOLOCK) ON stu.CustomerId = det.CustomerId
                                                   AND stu.StudentId = det.StudentId
     INNER JOIN tb_Contact_Channel_Mapping map WITH (NOLOCK) ON det.CustomerId = map.CustomerId
                                                            AND det.StudentId = map.StudentId
                                                            AND det.ContactId = map.ContactId
     INNER JOIN tb_Contact_Fields field WITH (NOLOCK) ON det.CustomerId = field.CustomerId
                                                     AND det.ContactId = map.ContactId
WHERE stud.CustomerId = @CustomerId
  AND map.ChannelId = @ChannelId;

For ChannelId=1, CustomerCode=1
Result id EmailCount 2, PhoneCount 1, SMSCount 2

此查询经常在多个工作流程中使用。然而,现在观察到的问题是,随着学生、联系人和频道的记录不断增加,此查询的结果会变慢并超时。是否有任何性能改进或替代方案可以建议?

【问题讨论】:

  • 出于兴趣,你为什么对每张桌子都使用NOLOCK?我希望 " 此查询的结果会变慢并超时。" 不是原因;因为它很可能会让你的结果出错,而不是更快。
  • 不是性能问题,而是小心地将 NOLOCK 溅到各处。这不是一个神奇的快速按钮。它有一些非常严重的副作用。诸如随机返回丢失和/或重复的行之类的事情。提示可以做一连串其他“有趣”的事情。 sentryone.com/blog/aaronbertrand/bad-habits-nolock-everywhere
  • 查看查询执行计划,看看是否建议添加任何键或索引。
  • 对于手头的任务,是的,随着添加更多行,查询会变慢。我的猜测是你在这里没有一个好的索引策略。也许您可以分享执行计划? brentozar.com/pastetheplan
  • 您是否尝试过通过 WHERE ...field.FieldType IN('Email', 'Phone','SMS') 排除记录,可能在某处的索引中使用 FieldType - 只有这些记录在最终输出

标签: sql sql-server


【解决方案1】:
SELECT @EmailCnt = ISNULL(SUM(CASE 
                WHEN field.FieldType = 'Email'
                    THEN 1
                ELSE 0
                END), 0)
    ,@PhoneCnt = ISNULL(SUM(CASE 
                WHEN field.FieldType = 'Phone'
                    THEN 1
                ELSE 0
                END), 0)
    ,@SMSCnt = ISNULL(SUM(CASE 
                WHEN field.FieldType = 'SMS'
                    THEN 1
                ELSE 0
                END), 0)
FROM tb_Students stu WITH (NOLOCK)
INNER JOIN tb_Contact_Detail det WITH (NOLOCK) ON stu.CustomerId = det.CustomerId
    AND stu.StudentId = det.StudentId
INNER JOIN tb_Contact_Channel_Mapping map WITH (NOLOCK) ON det.CustomerId = map.CustomerId
    AND det.StudentId = map.StudentId
    AND det.ContactId = map.ContactId
INNER JOIN tb_Contact_Fields field WITH (NOLOCK) ON det.CustomerId = field.CustomerId
    AND field.FieldType IN (
        'Email'
        ,'Phone'
        ,'SMS'
        )
WHERE stud.CustomerId = @CustomerId
    AND map.ChannelId = @ChannelId

在这里,第二个 'AND det.ContactId = map.ContactId' 我不理解这样做的必要性,因为逻辑存在于另一个 JOIN 中。此外,我只加入感兴趣的“FieldType”。您可能想检查是否可以通过索引来辅助

我希望它有所帮助。

【讨论】:

  • Cato,让我试试这两个建议。谢谢。
  • Cato 这确实有点帮助,因为我有 6 个选项,这确实提供了一些改进。
  • @DeeP,Cato 很好地观察到。早期它试图获取比要求更多的记录,所以它很慢。现在只有它返回要求结果集,所以它必须改进。如果你需要进一步改进,那么你说不。每个表中的记录。现有索引、连接中使用的数据类型等。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多