【问题标题】:Alternate way of Exists with Having clauseExists with having 子句的替代方式
【发布时间】:2016-06-13 18:26:23
【问题描述】:

以下查询是检索 (SGT_DISBURSEMENT_REQUEST) 计数仅为 1 的记录。它工作得很好。但在性能方面,因为我们有 100 000 条记录,所以并没有花费太多时间。

有没有更好的办法?

   SELECT PA.PERSON_ID,
   PA.PERSON_ACCOUNT_ID,
   DR.DISBURSEMENT_REQUEST_ID,
   SUM
   (  
        ISNULL(CD.EE_PRE_TAX_AMT,0) + 
        ISNULL(CD.EE_ADDL_PRE_TAX_AMT,0)
   ) AS EE_PRE_TAX_CONTRIB,
   DD.PRE_TAX_AMOUNT AS DISB_DTL_PRE_TAX_AMOUNT,
   SUM
   (     ISNULL(CD.EE_POST_TAX_AMT,0) + 
         ISNULL(CD.EE_ADDL_POST_TAX_AMT,0)
   ) AS EE_POST_TAX_CONTRIB,
   DD.POST_TAX_AMOUNT AS DISB_DTL_POST_TAX_AMOUNT
   FROM SGT_DISBURSEMENT_REQUEST DR
   INNER JOIN SGT_DISBURSEMENT_DETAIL DD ON DR.DISBURSEMENT_REQUEST_ID = DD.DISBURSEMENT_REQUEST_ID 
   INNER JOIN SGT_PERSON_ACCOUNT PA ON PA.PERSON_ACCOUNT_ID = DR.PERSON_ACCOUNT_ID
   INNER JOIN SGT_CONTRIB_DTL CD ON CD.PERSON_ACCOUNT_ID = PA.PERSON_ACCOUNT_ID 
   WHERE DR.REQUEST_CATEGORY_VALUE = 'REFD' AND
         DD.DETAIL_CATEGORY_VALUE = 'REFD' AND
         CD.STATUS_VALUE = 'VALD' AND
         CD.POSTED_DATE <= DR.ACCEPTED_TO_PAYROLL_DATE AND
         DR.DISBURSEMENT_STATUS_VALUE <> 'CANL' AND
      EXISTS
        (
            SELECT 1 FROM SGT_DISBURSEMENT_REQUEST SDR1 
            INNER JOIN SGT_DISBURSEMENT_DETAIL SDD1 ON SDD1.DISBURSEMENT_REQUEST_ID = SDR1.DISBURSEMENT_REQUEST_ID
            WHERE SDR1.PERSON_ACCOUNT_ID = DR.PERSON_ACCOUNT_ID and SDD1.DETAIL_CATEGORY_VALUE = DD.DETAIL_CATEGORY_VALUE
            GROUP BY SDR1.PERSON_ACCOUNT_ID 
            HAVING COUNT(*) = 1
        )
   GROUP BY 
        PA.PERSON_ID, PA.PERSON_ACCOUNT_ID, DR.DISBURSEMENT_REQUEST_ID, DD.PRE_TAX_AMOUNT, DD.POST_TAX_AMOUNT

【问题讨论】:

    标签: sql sql-server-2008 sql-server-2005


    【解决方案1】:

    为了提高性能,您可以在 Join 子句中使用过滤条件,而不是 where 子句。在这种情况下,每个连接都会将结果限制为更少的行数。

            SELECT PA.PERSON_ID,
               PA.PERSON_ACCOUNT_ID,
               DR.DISBURSEMENT_REQUEST_ID,
               SUM
               (  
                    ISNULL(CD.EE_PRE_TAX_AMT,0) + 
                    ISNULL(CD.EE_ADDL_PRE_TAX_AMT,0)
               ) AS EE_PRE_TAX_CONTRIB,
               DD.PRE_TAX_AMOUNT AS DISB_DTL_PRE_TAX_AMOUNT,
               SUM
               (     ISNULL(CD.EE_POST_TAX_AMT,0) + 
                     ISNULL(CD.EE_ADDL_POST_TAX_AMT,0)
               ) AS EE_POST_TAX_CONTRIB,
               DD.POST_TAX_AMOUNT AS DISB_DTL_POST_TAX_AMOUNT
               FROM SGT_DISBURSEMENT_REQUEST DR
               INNER JOIN SGT_DISBURSEMENT_DETAIL DD ON     DR.DISBURSEMENT_REQUEST_ID = DD.DISBURSEMENT_REQUEST_ID AND DR.REQUEST_CATEGORY_VALUE = 'REFD' AND
                     DD.DETAIL_CATEGORY_VALUE = 'REFD' AND DR.DISBURSEMENT_STATUS_VALUE <> 'CANL'
               INNER JOIN SGT_PERSON_ACCOUNT PA ON PA.PERSON_ACCOUNT_ID = DR.PERSON_ACCOUNT_ID
               INNER JOIN SGT_CONTRIB_DTL CD ON CD.PERSON_ACCOUNT_ID = PA.PERSON_ACCOUNT_ID AND CD.STATUS_VALUE = 'VALD' AND
                     CD.POSTED_DATE <= DR.ACCEPTED_TO_PAYROLL_DATE
               WHERE EXISTS
                    (
                        SELECT 1 FROM SGT_DISBURSEMENT_REQUEST SDR1 
                        INNER JOIN SGT_DISBURSEMENT_DETAIL SDD1 ON SDD1.DISBURSEMENT_REQUEST_ID = SDR1.DISBURSEMENT_REQUEST_ID
                        WHERE SDR1.PERSON_ACCOUNT_ID = DR.PERSON_ACCOUNT_ID and SDD1.DETAIL_CATEGORY_VALUE = DD.DETAIL_CATEGORY_VALUE
                        GROUP BY SDR1.PERSON_ACCOUNT_ID 
                        HAVING COUNT(*) = 1
                    )
               GROUP BY 
                    PA.PERSON_ID, PA.PERSON_ACCOUNT_ID, DR.DISBURSEMENT_REQUEST_ID, DD.PRE_TAX_AMOUNT, DD.POST_TAX_AMOUNT
    

    【讨论】:

      【解决方案2】:

      如果你使用 count over 它应该会给你相同的结果并且更好的性能:

      select * from (
      SELECT PA.PERSON_ID,
         PA.PERSON_ACCOUNT_ID,
         DR.DISBURSEMENT_REQUEST_ID,
         SUM
         (  
              ISNULL(CD.EE_PRE_TAX_AMT,0) + 
              ISNULL(CD.EE_ADDL_PRE_TAX_AMT,0)
         ) AS EE_PRE_TAX_CONTRIB,
         DD.PRE_TAX_AMOUNT AS DISB_DTL_PRE_TAX_AMOUNT,
         SUM
         (     ISNULL(CD.EE_POST_TAX_AMT,0) + 
               ISNULL(CD.EE_ADDL_POST_TAX_AMT,0)
         ) AS EE_POST_TAX_CONTRIB,
         DD.POST_TAX_AMOUNT AS DISB_DTL_POST_TAX_AMOUNT
         ,count(*) over(partition by PA.PERSON_ACCOUNT_ID ) as  ct
         FROM SGT_DISBURSEMENT_REQUEST DR
         INNER JOIN SGT_DISBURSEMENT_DETAIL DD ON DR.DISBURSEMENT_REQUEST_ID = DD.DISBURSEMENT_REQUEST_ID 
         INNER JOIN SGT_PERSON_ACCOUNT PA ON PA.PERSON_ACCOUNT_ID = DR.PERSON_ACCOUNT_ID
         INNER JOIN SGT_CONTRIB_DTL CD ON CD.PERSON_ACCOUNT_ID = PA.PERSON_ACCOUNT_ID 
         WHERE DR.REQUEST_CATEGORY_VALUE = 'REFD' AND
               DD.DETAIL_CATEGORY_VALUE = 'REFD' AND
               CD.STATUS_VALUE = 'VALD' AND
               CD.POSTED_DATE <= DR.ACCEPTED_TO_PAYROLL_DATE AND
               DR.DISBURSEMENT_STATUS_VALUE <> 'CANL' 
      
         GROUP BY 
              PA.PERSON_ID, PA.PERSON_ACCOUNT_ID, DR.DISBURSEMENT_REQUEST_ID, DD.PRE_TAX_AMOUNT, DD.PRE_TAX_AMOUNT, DD.POST_TAX_AMOUNT
              ) as x 
      where x.ct = 1
      

      【讨论】:

        【解决方案3】:

        我会将其具体化为#temp

        SELECT DR1.PERSON_ACCOUNT_ID, SDD1.DETAIL_CATEGORY_VALUE
          FROM SGT_DISBURSEMENT_REQUEST SDR1 
          JOIN SGT_DISBURSEMENT_DETAIL SDD1 
                 ON SDD1.DISBURSEMENT_REQUEST_ID = SDR1.DISBURSEMENT_REQUEST_ID
         GROUP BY SDR1.PERSON_ACCOUNT_ID, SDD1.DETAIL_CATEGORY_VALUE 
        HAVING COUNT(*) = 1
        
        join #temp 
              on #temp.PERSON_ACCOUNT_ID = DR.PERSON_ACCOUNT_ID
             and #temp.DETAIL_CATEGORY_VALUE = DD.DETAIL_CATEGORY_VALUE
        

        【讨论】:

          猜你喜欢
          • 2015-09-06
          • 1970-01-01
          • 1970-01-01
          • 2011-04-01
          • 1970-01-01
          • 1970-01-01
          • 2019-01-15
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多