请复制并粘贴以下脚本。
DECLARE @MainTable TABLE(MainTablePkId int)
INSERT INTO @MainTable SELECT 1
INSERT INTO @MainTable SELECT 2
DECLARE @SomeTable TABLE(SomeIdPk int, MainTablePkId int, ViewedTime1 datetime)
INSERT INTO @SomeTable SELECT 1, 1, DATEADD(dd, -10, getdate())
INSERT INTO @SomeTable SELECT 2, 1, DATEADD(dd, -9, getdate())
INSERT INTO @SomeTable SELECT 3, 2, DATEADD(dd, -6, getdate())
DECLARE @SomeTableDetail TABLE(DetailIdPk int, SomeIdPk int, Viewed INT, ViewedTimeDetail datetime)
INSERT INTO @SomeTableDetail SELECT 1, 1, 1, DATEADD(dd, -7, getdate())
INSERT INTO @SomeTableDetail SELECT 2, 2, NULL, DATEADD(dd, -6, getdate())
INSERT INTO @SomeTableDetail SELECT 3, 2, 2, DATEADD(dd, -8, getdate())
INSERT INTO @SomeTableDetail SELECT 4, 3, 1, DATEADD(dd, -6, getdate())
SELECT m.MainTablePkId,
(SELECT COUNT(Viewed) FROM @SomeTableDetail),
(SELECT TOP 1 s2.ViewedTimeDetail FROM @SomeTableDetail s2
INNER JOIN @SomeTable s1 ON s2.SomeIdPk = s1.SomeIdPk
WHERE s1.MainTablePkId = m.MainTablePkId)
FROM @MainTable m
此脚本只是一个示例。我在SELECT
中有很长的列列表,在子查询中有大约12列以上的列。在我的From
子句中,大约有8个表。
要获取2000条记录,完整查询需要21秒,如果我删除子查询,则需要4秒。
我尝试使用“数据库引擎优化顾问”优化查询以及添加新的建议索引和统计信息,但这些更改会使查询时间变得更糟。
注意:
正如我已经提到的,这是用于解释我的问题的测试数据,真实数据有很多表连接列但没有子查询结果我们没问题。
任何帮助谢谢。
答案 0 :(得分:2)
相关的子查询按行逐行运行,你所拥有的基本上是你的proc中的很多游标。将它们更改为连接(或连接到派生表或CTE)。 使用性能标准中的相关子查询是一种不好的做法。它们总是可以用连接,CTE或派生表连接替换。
答案 1 :(得分:2)
这是一个CTE示例,它接近您所拥有但不完全符合您的要求但可以帮助您入门。
WITH _CountViewed AS
(
SELECT COUNT(Viewed) AS Viewed FROM @SomeTableDetail
),
_SomeDate AS
(
SELECT MAX(s2.ViewedTimeDetail) As ChangeTime, s1.MainTablePkId FROM @SomeTableDetail s2
INNER JOIN @SomeTable s1 ON s2.SomeIdPk = s1.SomeIdPk
GROUP BY s1.MainTablePkId
)
SELECT sd.MainTablePkId, cv.Viewed, sd.ChangeTime FROM _SomeDate sd
OUTER APPLY _CountViewed cv
答案 2 :(得分:0)
我试图在线条之间稍微阅读并填补空白,但我认为这可能更接近你想要完成的事情。
SELECT m.MainTablePkId, SUM(std.Viewed), MAX(std.ViewedTimeDetail)
FROM @MainTable m
INNER JOIN @SomeTable st
ON m.MainTablePkId = st.MainTablePkId
INNER JOIN @SomeTableDetail std
ON st.SomeIdPk = std.SomeIdPk
GROUP BY m.MainTablePkId
答案 3 :(得分:0)
如果它们没有被正式声明为PK,我会在s1.MainTablePkId和m.MainTablePkId,s2.SomeIdPk和s1.SomeIdPk上创建索引。 (已经由sql server索引)
你可以通过添加(nolock)来进行非锁定读取,它会通过不锁定表来加速它。
SELECT m.MainTablePkId,
(SELECT COUNT(Viewed) FROM @SomeTableDetail (nolock)),
(SELECT TOP 1 s2.ViewedTimeDetail FROM @SomeTableDetail s2 (nolock)
INNER JOIN @SomeTable s1 (nolock) ON s2.SomeIdPk = s1.SomeIdPk
WHERE s1.MainTablePkId = m.MainTablePkId)
FROM @MainTable m (nolock)