【问题标题】:Poorly performing SQL query性能不佳的 SQL 查询
【发布时间】:2026-02-08 22:30:02
【问题描述】:

我有如下查询,在 SQL Server 2008 中执行

SELECT
    ipm.HEORG_REFNO,    
    ipm.HOTYP_REFNO,     
    ipm.CASLT_REFNO,     
    ipm.HOLVL_REFNO,    
    IPM.MAIN_IDENT,  
     ...  
FROM  
    dbo.HEALTH_ORGANISATIONS ipm  (NOLOCK)             
LEFT JOIN
    (SELECT
         s.heorg_refno, min(s.start_dttm) as start_dttm_SPONT, max(isnull(convert(datetime,s.end_dttm,120),convert(datetime,'9999-01-01', 120))) as end_dttm_SPONT    
     FROM
         dbo.service_points s (NOLOCK)    
     INNER JOIN
         dbo.reference_values rfval (NOLOCK) ON s.SPTYP_REFNO = rfval.RFVAL_REFNO    
                                             AND RFVAL.MAIN_CODE != 'PDT'         
     GROUP BY 
         s.heorg_refno) SPONT ON ipm.HEORG_REFNO = SPONT.HEORG_REFNO    

 -- Bring only Health Organisation records and also certain records,whose HOTYP_REFNO does not exist in REF_VALS
WHERE
    NOT EXISTS ((SELECT 'x' 
                 FROM REFERENCE_VALUES RVAL (NOLOCK) 
                 WHERE RVAL.RFVAL_REFNO = ipm.HOTYP_REFNO 
                   AND main_code IN ('011','012','015','016',  '017','019','2','AANDE','AEB','AEC','CLINIC','DAYCC','DEPRT','GPSIT','HC','HOSPL','HOST','LOCTN','LOSYN','MIU','MISC','MRL', 'SITE','THEAT','WARD','PDT','NURHM','DAYCR') 
    or ipm.HEORG_REFNO IN(select distinct HEORG_REFNO from SERVICE_POINT_SESSIONS (NOLOCK) where OWNER_HEORG_REFNO = 2001934 and HEORG_REFNO != 2001934) 
    or ipm.HEORG_REFNO IN (select REFNO from LOR_IPM_SYNTH_STG_DEV..  STAGING_Activity_LOCATION_DCS (NOLOCK) where Sources='HEORG_REFNO' and REFNO != 2001934)  
    )
  )

执行查询需要花费大量时间。

当我评论以下 2 行时,它运行得更快:

or ipm.HEORG_REFNO IN(select distinct HEORG_REFNO from SERVICE_POINT_SESSIONS (NOLOCK) where OWNER_HEORG_REFNO = 2001934 and HEORG_REFNO != 2001934) 
    or ipm.HEORG_REFNO IN (select REFNO from LOR_IPM_SYNTH_STG_DEV..  STAGING_Activity_LOCATION_DCS (NOLOCK) where Sources='HEORG_REFNO' and REFNO != 2001934)  

感谢您在调整查询时提供的任何指导

【问题讨论】:

  • 不存在的选择部分是否需要永远自行运行?
  • 要改掉的坏习惯:putting NOLOCK everywhere。可能的影响:脏读、缺失行、两次读取行、读取同一行的多个版本、索引损坏、读取错误……
  • 不..它运行得非常快..

标签: sql-server-2008 query-performance


【解决方案1】:

我的第一个想法是您的查询非常复杂 - 我会寻找简化它的方法...

In 子句并不总是表现良好 - 我很想将这些信息吸进一个禁止的“main_Codes”表变量中,然后加入它并测试是否为空......

是时候运行执行计划,看看你的瓶颈实际在哪里,这取决于你自己的环境(索引、统计等)......

【讨论】:

    【解决方案2】:

    尝试将这些 IN 子查询转换为如下所示的 JOIN 查询,并确保在连接条件和 where 过滤条件涉及的所有列上创建了正确的索引。

    LEFT JOIN SERVICE_POINT_SESSIONS sps ON ipm.HEORG_REFNO = sps.HEORG_REFNO
    AND sps.OWNER_HEORG_REFNO = 2001934 
    AND sps.HEORG_REFNO != 2001934
    

    我会将您的查询修改为如下所示。尽管到目前为止我对您的大 inlist 无能为力,但您应该将该 inlist 拉入表变量中,并考虑用它来做 JOIN

    SELECT
        ipm.HEORG_REFNO,    
        ipm.HOTYP_REFNO,     
        ipm.CASLT_REFNO,     
        ipm.HOLVL_REFNO,    
        IPM.MAIN_IDENT,  
         ...  
    FROM  
        dbo.HEALTH_ORGANISATIONS ipm            
    LEFT JOIN
        (SELECT
             s.heorg_refno, min(s.start_dttm) as start_dttm_SPONT, 
             max(isnull(convert(datetime,s.end_dttm,120),convert(datetime,'9999-01-01', 120))) as end_dttm_SPONT    
         FROM
             dbo.service_points s     
         INNER JOIN dbo.reference_values rfval 
         ON s.SPTYP_REFNO = rfval.RFVAL_REFNO  
         AND RFVAL.MAIN_CODE != 'PDT'         
         GROUP BY 
             s.heorg_refno) SPONT ON ipm.HEORG_REFNO = SPONT.HEORG_REFNO
    
    LEFT JOIN SERVICE_POINT_SESSIONS sps 
    ON ipm.HEORG_REFNO = sps.HEORG_REFNO 
    AND sps.OWNER_HEORG_REFNO = 2001934 
    AND sps.HEORG_REFNO != 2001934
    
    LEFT JOIN LOR_IPM_SYNTH_STG_DEV .. STAGING_Activity_LOCATION_DCS sald 
    ON ipm.HEORG_REFNO = sald.HEORG_REFNO
    AND sald.Sources='HEORG_REFNO' 
    AND sald.REFNO != 2001934
    
    WHERE NOT EXISTS (SELECT 1 
                     FROM REFERENCE_VALUES RVAL 
                     WHERE RVAL.RFVAL_REFNO = ipm.HOTYP_REFNO 
                     AND RVAL.main_code IN ('011','012','015','016',  '017','019','2','AANDE','AEB','AEC','CLINIC','DAYCC','DEPRT','GPSIT','HC','HOSPL','HOST','LOCTN','LOSYN','MIU','MISC','MRL', 'SITE','THEAT','WARD','PDT','NURHM','DAYCR')); 
    

    【讨论】:

    • 抱歉.. 将其设为左连接无济于事.. 而且我们对 DB 没有任何权限.. 它的“只读”用于所有实际用途...
    • 对不起..它没有..我基本上是在检查服务点会话表中不存在来自 ipm 的记录..我什至添加了一个“WHERE SPSSN.HEORG_REFNO IS NULL”子句..但它仍然没有提供所需的输出..