性能不佳的 SQL 查询
Posted
技术标签:
【中文标题】性能不佳的 SQL 查询【英文标题】:Poorly performing SQL query 【发布时间】:2016-01-05 11:36:45 【问题描述】:我有如下查询,在 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)
感谢您在调整查询时提供的任何指导
【问题讨论】:
不存在的选择部分是否需要永远自行运行? 要改掉的坏习惯:puttingNOLOCK
everywhere。可能的影响:脏读、缺失行、两次读取行、读取同一行的多个版本、索引损坏、读取错误……
不..它运行得非常快..
【参考方案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”子句..但它仍然没有提供所需的输出..以上是关于性能不佳的 SQL 查询的主要内容,如果未能解决你的问题,请参考以下文章
Windows 上 localtime_s() 多线程性能不佳的解决方法