我有以下两个查询-原来是第一个,第二个是我的轻微"升级"。第一个花了将近一秒钟的时间运行,第二个在我的手指完全离开刷新按钮之前就结束了。
我的问题:为什么?
第一个和第二个之间的唯一区别是第一个使用coalesce来获得一个值来比较berp。ID_PART_SESSION with和第二个使用联合将两个select语句放在一起来完成相同的任务。
我仍然认为第一个应该更快(我使用coalesce的最初原因),因为它似乎应该做更少的工作来获得相同的结果。考虑到我破译执行计划的能力有多弱,有人能解释一下为什么第二个查询比第一个查询好得多吗?
declare @animator varchar
SELECT TOP 1 @animator = FULL_NAME
FROM T_BERP berp
INNER JOIN dbo.T_INTERV i ON i.ID_INTERV = berp.ID_INTERV
WHERE berp.VERSION = 1
AND berp.PRINCIPAL = 1
AND berp.DELETED = 0
AND berp.CANCELLED = 0
AND berp.ID_PART_SESSION = (
select coalesce(pss.ID_PART_SESSION, psst.ID_PART_SESSION)
from t_bersp b
LEFT JOIN T_PART_SESSION pss ON b.ID_PART_SESSION = pss.ID_PART_SESSION
LEFT JOIN T_PSS_TEMP psst ON b.ID_PSS_TEMP = psst.ID_PSS_TEMP
where ID_BERSP = 4040)
和
declare @animator varchar
SELECT TOP 1 @animator = FULL_NAME
FROM dbo.T_BERP berp
INNER JOIN dbo.T_INTERV i ON i.ID_INTERV = berp.ID_INTERV
WHERE berp.VERSION = 1
AND berp.PRINCIPAL = 1
AND berp.DELETED = 0
AND berp.CANCELLED = 0
AND berp.ID_PART_SESSION IN (
select pss.ID_PART_SESSION
from dbo.t_bersp b
LEFT JOIN dbo.T_PART_SESSION pss ON b.ID_PART_SESSION = pss.ID_PART_SESSION
where ID_BERSP = 4040
union
select psst.ID_PART_SESSION
from dbo.t_bersp b
LEFT JOIN dbo.T_PSS_TEMP psst ON b.ID_PSS_TEMP = psst.ID_PSS_TEMP
where ID_BERSP = 4040)
如果不了解查询中各种表的相对大小和索引,就很难给出明确的答案。一种可能性是:如果t_part_session和t_pss_temp都很大,查询优化器可能对第一个查询的内部SELECT中的两个LEFT join做了一些效率低下的事情。
编辑澄清:是的,在两个查询中都有LEFT join,但我的猜测是,有两个在一起(查询1)可能会对性能产生不利影响,而不是UNION(查询2)。对不起,如果最初不清楚。
另外,我强烈推荐一个工具,如即时SQL格式化器(结合{}图标在StackOverflow的编辑器),使查询在你的问题更容易阅读:
DECLARE @animator VARCHAR
SELECT TOP 1 @animator = full_name
FROM t_berp berp
INNER JOIN dbo.t_interv i
ON i.id_interv = berp.id_interv
WHERE berp.version = 1
AND berp.principal = 1
AND berp.deleted = 0
AND berp.cancelled = 0
AND berp.id_part_session = (SELECT
Coalesce(pss.id_part_session, psst.id_part_session)
FROM t_bersp b
LEFT JOIN t_part_session pss
ON b.id_part_session =
pss.id_part_session
LEFT JOIN t_pss_temp psst
ON b.id_pss_temporaire =
psst.id_pss_temporaire
WHERE id_bersp = 4040)
和
DECLARE @animator VARCHAR
SELECT TOP 1 @animator = full_name
FROM dbo.t_berp berp
INNER JOIN dbo.t_interv i
ON i.id_interv = berp.id_interv
WHERE berp.version = 1
AND berp.principal = 1
AND berp.deleted = 0
AND berp.cancelled = 0
AND berp.id_part_session IN (SELECT pss.id_part_session
FROM dbo.t_bersp b
LEFT JOIN dbo.t_part_session pss
ON b.id_part_session =
pss.id_part_session
WHERE id_bersp = 4040
UNION
SELECT psst.id_part_session
FROM dbo.t_bersp b
LEFT JOIN dbo.t_pss_temp psst
ON b.id_pss_temporaire =
psst.id_pss_temporaire
WHERE id_bersp = 4040)
我打赌这是合并语句。我相信合并最终会在where子句之前应用。因此,它实际上遍历两个表的每个组合,然后对匹配where子句的表进行过滤。
您可以在SSMS中将这两个查询放到同一个批处理中并显示执行计划——这不仅可以让您并排查看它们,还可以显示相对成本。
我怀疑IN (UNION)意味着第二个可以很容易地并行化。