我有这个查询有效,但很慢
SELECT
ID_NODE,
-- this case slows down the query!!!
CASE WHEN (EXISTS (SELECT MV.ID_CHILD FROM MYVIEW MV INNER JOIN MYTABLE1 MT1 ON MT1.ID_NODE = MV.ID_CHILD WHERE MV.ID_PARENT = CA.ID_NODE AND ID_FATHER IS NOT NULL)) THEN 'Y' ELSE 'N' END AS HAVE_CHILDREN,
OTHER_FIELDS
FROM
MYTABLE2
更新:在第一个回答后,我意识到我的示例并不完美,所以我修改了它做了2次更改(CA
到MT1
,然后写{{1} }而不是MT1.ID_FATHER
)
ID_FATHER
更新结束
基本上我想要一个 SELECT
ID_NODE,
-- this case slows down the query!!!
CASE WHEN (EXISTS (SELECT MV.ID_CHILD FROM MYVIEW MV INNER JOIN MYTABLE1 MT1 ON MT1.ID_NODE = MV.ID_CHILD WHERE MV.ID_PARENT = MT2.ID_NODE AND MT1.ID_FATHER IS NOT NULL)) THEN 'Y' ELSE 'N' END AS HAVE_CHILDREN,
OTHER_FIELDS
FROM
MYTABLE2
结果“这个节点有孩子吗?
在执行计划中,我只看到一个警告:
嵌套循环(内连接))43%
您能否建议改进查询?
作为exterme解决方案,我可以将'y'/'n'
值存储在表中作为新字段,但我不喜欢这样,因为它是“通向错误的公路”。
Bounty注意事项:
我在这里发布原始表,视图(用CREATE语句制作)和查询以帮助提供回复:
HAVE_CHILDREN
答案 0 :(得分:2)
SELECT
CA.ID_CESPITE,
CASE WHEN child.[Count] > 0 THEN 'Y' ELSE 'N' END AS HAVE_CHILD_PRG,
CA.ID_CESPITE_PADRE
FROM
CES_ANAGRAFICA CA
LEFT OUTER JOIN CES_PERMESSI CP
ON ((CA.ID_CESPITE = CP.ID_CESPITE))
INNER JOIN CES_TIPI_CESPITE CTCS
ON CA.ID_TIPO_CESPITE = CTCS.ID_TIPI_INFRSTR
LEFT OUTER JOIN V_UTENTI_DIPENDENTI VUD
ON CA.ID_RESPONSABILE = VUD.ID_DIPENDENTE
CROSS APPLY (
SELECT [Count] = COUNT(*)
FROM V_CESPITE_TREE VCA
JOIN MAN_PRG_OPERAZIONI MPO
ON MPO.ID_CESPITE = VCA.ID_CHILD
WHERE VCA.ID_PARENT = CA.ID_CESPITE
AND MPO.ID_FATHER is not null
) child
这应该稍微好一点,因为它不必执行聚合函数。
SELECT
CA.ID_CESPITE,
CASE WHEN child.[Exists] = 1 THEN 'Y' ELSE 'N' END AS HAVE_CHILD_PRG,
CA.ID_CESPITE_PADRE
FROM
CES_ANAGRAFICA CA
LEFT OUTER JOIN CES_PERMESSI CP
ON ((CA.ID_CESPITE = CP.ID_CESPITE))
INNER JOIN CES_TIPI_CESPITE CTCS
ON CA.ID_TIPO_CESPITE = CTCS.ID_TIPI_INFRSTR
LEFT OUTER JOIN V_UTENTI_DIPENDENTI VUD
ON CA.ID_RESPONSABILE = VUD.ID_DIPENDENTE
OUTER APPLY (
SELECT TOP (1) 1 [Exists]
FROM V_CESPITE_TREE VCA
JOIN MAN_PRG_OPERAZIONI MPO
ON MPO.ID_CESPITE = VCA.ID_CHILD
WHERE VCA.ID_PARENT = CA.ID_CESPITE
AND MPO.ID_FATHER is not null
) child
答案 1 :(得分:0)
使用CTE;它会加载你的内连接一次,然后缓存它。
注意我不知道CA.ID_NODE来自哪里,因为你没有解释。 你的内部查询也加入了MyTable1,但是你没有关联MyTable2和子查询。
假设您提供的内容,伪代码应该是这样的: (如果您使用相关信息更新您的问题,我会更新此答案以反映它。)
<强>更新强>
这是基于您的架构更新和一些示例数据的更新版本。我确认这不再导致重复。真正的问题是你检查它并确保它提高了性能,又降低了执行时间。
; with hasChildCte(ID_CESPITE, ID_PARENT)
As (
SELECT VCA.ID_CHILD,
vca.ID_PARENT
FROM V_CESPITE_TREE VCA
INNER JOIN MAN_PRG_OPERAZIONI MPO
ON MPO.ID_CESPITE = VCA.ID_CHILD
WHERE ID_FATHER
IS NOT NULL
)
Select
CA.ID_CESPITE,
Case
When Exists (
Select ID_PARENT
From hasChildCte cte
Where cte.ID_PARENT = ca.ID_CESPITE
) Then 'Y'
Else 'N'
End As HAVE_CHILDREN,
CA.ID_CESPITE_PADRE
From CES_ANAGRAFICA CA
另请注意,如果您没有在所有已加入的列上都有索引,那么将它们放入其中将是一个很好的举措。这将有助于进一步加快查询速度,尤其是如果您正在使用大量的数据
更新2
关于CTE执行不止一次的评论让我思考,显然由SQL服务器决定是否缓存CTE,而不是总是缓存。在许多情况下,CTE只会执行一次,但有时候它与SQL服务器中的视图类似,并且不会被缓存。
因此,我修改了代码以使用table variable
代替。但是,我没有足够的测试数据来查看哪种表现更好或更快。
试试这个,看看它是否会产生更快的查询执行时间。另请注意,无论您选择哪种重构方法和性能改进,最好使用JOIN中使用的列上的索引正确设置数据库。这会显着增加查询执行时间,而且必须更新索引的插入成本很低。
更新的非CTE代码,改为使用表变量:
Declare @HasChildren table (ID_CESPITE int, ID_PARENT int)
Insert into @HasChildren
Select VCA.ID_CHILD,
vca.ID_PARENT
From V_CESPITE_TREE VCA
Inner Join MAN_PRG_OPERAZIONI MPO
On MPO.ID_CESPITE = VCA.ID_CHILD
Where ID_FATHER
Is Not Null
Select
CA.ID_CESPITE,
Case
When Exists (
Select ID_PARENT
From @HasChildren c
Where c.ID_PARENT = ca.ID_CESPITE
) Then 'Y'
Else 'N'
End As HAVE_CHILDREN,
CA.ID_CESPITE_PADRE
From CES_ANAGRAFICA CA
答案 2 :(得分:0)
优化器可以更轻松地处理以下内容。
SELECT DISTINCT
ID_NODE,
CASE WHEN MTSub.ID_CHILD is null then 'N' else 'Y' END,
OTHERFIELDS
FROM MYTABLE2
LEFT JOIN
(SELECT MV.ID_CHILD FROM MYVIEW MV INNER JOIN MYTABLE1 MT1 ON MT1.ID_NODE = MV.ID_CHILD WHERE MV.ID_PARENT = MT2.ID_NODE AND MT1.ID_FATHER IS NOT NULL) MTSub