使用多个 OUTER APPLY 优化查询
Optimize query with multiple OUTER APPLY
我有多个 OUTER APPLY
的查询,但所有 table 的连接列上都有主键(所以这里使用聚集索引)所以我不知道如何优化这个查询进一步。此外,在这里使用索引视图是不可能的,因为使用 ORDER BY
和 TOP
是被禁止的。
所以我有
Table Fields
带有 Id
主键和大量其他列。
WeatherHistory
table 具有复杂的主键(FieldId
和 [Date]
)和很多列,
NdviImageHistory
table 与 FieldId
、[Date]
、[Base64]
列(复杂主键 FieldId
和 [Date]
) 其中 [Base64]
存储图像 base64,
NaturalColorImageHistory
table 与 FieldId
、[Date]
、[Base64]
列(复杂主键 FieldId
和 [Date]
) 其中 [Base64]
存储图像 base64,
NdviHistory
table with with with FieldId
, [Date]
, MeanNdvi
列(复杂主键 FieldId
和[Date]
),
FieldSeasonHistory
table 与 Field
、StartDate
、EndDate
列(复杂主键 FieldId
和 [Date]
).
我的查询
SELECT Fields.*,
WeatherHistory.TempSumC AS CurrentTempSumC,
TempSumF AS CurrentTempSumF,
PrecipitationSumMm AS CurrentPrecipitationSumMm,
nih.[Base64] AS CurrentNdviImageBase64,
ncih.[Base64] AS CurrentNaturalColorImageBase64,
MeanNdvi AS CurrentMeanNdvi,
IsOpenSeason
FROM Fields
LEFT JOIN WeatherHistory ON FieldId = Id AND [Date] = CAST(GETUTCDATE() AS DATE)
OUTER APPLY
(
SELECT TOP 1 [Base64]
FROM NdviImageHistory
WHERE FieldId = Id
ORDER BY [Date] DESC
) nih
OUTER APPLY
(
SELECT TOP 1 [Base64]
FROM NaturalColorImageHistory
WHERE FieldId = Id
ORDER BY [Date] DESC
) ncih
OUTER APPLY
(
SELECT TOP 1 MeanNdvi
FROM NdviHistory
WHERE FieldId = Id
ORDER BY [Date] DESC
) nh
OUTER APPLY
(
SELECT TOP 1 CASE WHEN EndDate IS NULL THEN 1 ELSE 0 END AS IsOpenSeason
FROM FieldSeasonHistory
WHERE FieldId = Id
ORDER BY [StartDate] DESC
) fsh
WHERE UserId = (SELECT Id FROM Users WHERE Email = @email) AND IsArchived = 0
我没有创建任何索引,因为我认为自动生成的聚簇索引(基于主键)应该足够了(但我可能是错的)。此查询执行大约 15 秒,但我想减少查询时间。
编辑: 向 Fields
table 的 UserId
和 IsArchived
列添加了索引。查询执行计划:
** 编辑 2:** 统计数据:
SQL Server parse and compile time:
CPU time = 0 ms, elapsed time = 0 ms.
SQL Server Execution Times:
CPU time = 0 ms, elapsed time = 0 ms.
SQL Server parse and compile time:
CPU time = 0 ms, elapsed time = 0 ms.
SQL Server Execution Times:
CPU time = 0 ms, elapsed time = 0 ms.
SQL Server Execution Times:
CPU time = 0 ms, elapsed time = 0 ms.
SQL Server Execution Times:
CPU time = 0 ms, elapsed time = 0 ms.
(13 row(s) affected)
Table 'FieldSeasonHistory'. Scan count 13, logical reads 26, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'NdviHistory'. Scan count 13, logical reads 26, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'NaturalColorImageHistory'. Scan count 13, logical reads 26, physical reads 0, read-ahead reads 0, lob logical reads 604, lob physical reads 0, lob read-ahead reads 0.
Table 'NdviImageHistory'. Scan count 13, logical reads 39, physical reads 0, read-ahead reads 0, lob logical reads 68, lob physical reads 0, lob read-ahead reads 0.
Table 'WeatherHistory'. Scan count 0, logical reads 39, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Users'. Scan count 0, logical reads 228, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Fields'. Scan count 1, logical reads 19, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
(1 row(s) affected)
SQL Server Execution Times:
CPU time = 15 ms, elapsed time = 16 ms.
SQL Server parse and compile time:
CPU time = 0 ms, elapsed time = 0 ms.
SQL Server Execution Times:
CPU time = 0 ms, elapsed time = 0 ms.
您需要为每个表创建多列索引。索引应该是 where 中的列,order by
中的列,然后是 select
中的列。例如:
NdviImageHistory(FieldId, [Date], [Base64])
NaturalColorImageHistory(FieldId, [Date], [Base64])
- 等等。
像这样更新您的查询。
SELECT Fields.*,
WeatherHistory.TempSumC AS CurrentTempSumC,
TempSumF AS CurrentTempSumF,
PrecipitationSumMm AS CurrentPrecipitationSumMm,
nih.[Base64] AS CurrentNdviImageBase64,
ncih.[Base64] AS CurrentNaturalColorImageBase64,
MeanNdvi AS CurrentMeanNdvi,
IsOpenSeason
FROM Fields
LEFT JOIN WeatherHistory ON FieldId = Id AND [Date] = CAST(GETUTCDATE() AS DATE)
OUTER APPLY
(
SELECT MAX(NdviImageHistory.ID) MAX_ID
FROM NdviImageHistory
WHERE FieldId = Id
) nih_ID
OUTER APPLY
(
SELECT [Base64] FROM NdviImageHistory X WHERE X.ID = nih_ID.MAX_ID
)nih
用户更多外部申请所有这些表 {nih , ncih, nh, fsh }
试试这个。
我只为 [nih] 使用 1 个外层
从 OUTER APPLY Joins 中删除 TOP 1 和 Order by
我有多个 OUTER APPLY
的查询,但所有 table 的连接列上都有主键(所以这里使用聚集索引)所以我不知道如何优化这个查询进一步。此外,在这里使用索引视图是不可能的,因为使用 ORDER BY
和 TOP
是被禁止的。
所以我有
Table
Fields
带有Id
主键和大量其他列。WeatherHistory
table 具有复杂的主键(FieldId
和[Date]
)和很多列,NdviImageHistory
table 与FieldId
、[Date]
、[Base64]
列(复杂主键FieldId
和[Date]
) 其中[Base64]
存储图像 base64,NaturalColorImageHistory
table 与FieldId
、[Date]
、[Base64]
列(复杂主键FieldId
和[Date]
) 其中[Base64]
存储图像 base64,NdviHistory
table with with withFieldId
,[Date]
,MeanNdvi
列(复杂主键FieldId
和[Date]
),FieldSeasonHistory
table 与Field
、StartDate
、EndDate
列(复杂主键FieldId
和[Date]
).
我的查询
SELECT Fields.*,
WeatherHistory.TempSumC AS CurrentTempSumC,
TempSumF AS CurrentTempSumF,
PrecipitationSumMm AS CurrentPrecipitationSumMm,
nih.[Base64] AS CurrentNdviImageBase64,
ncih.[Base64] AS CurrentNaturalColorImageBase64,
MeanNdvi AS CurrentMeanNdvi,
IsOpenSeason
FROM Fields
LEFT JOIN WeatherHistory ON FieldId = Id AND [Date] = CAST(GETUTCDATE() AS DATE)
OUTER APPLY
(
SELECT TOP 1 [Base64]
FROM NdviImageHistory
WHERE FieldId = Id
ORDER BY [Date] DESC
) nih
OUTER APPLY
(
SELECT TOP 1 [Base64]
FROM NaturalColorImageHistory
WHERE FieldId = Id
ORDER BY [Date] DESC
) ncih
OUTER APPLY
(
SELECT TOP 1 MeanNdvi
FROM NdviHistory
WHERE FieldId = Id
ORDER BY [Date] DESC
) nh
OUTER APPLY
(
SELECT TOP 1 CASE WHEN EndDate IS NULL THEN 1 ELSE 0 END AS IsOpenSeason
FROM FieldSeasonHistory
WHERE FieldId = Id
ORDER BY [StartDate] DESC
) fsh
WHERE UserId = (SELECT Id FROM Users WHERE Email = @email) AND IsArchived = 0
我没有创建任何索引,因为我认为自动生成的聚簇索引(基于主键)应该足够了(但我可能是错的)。此查询执行大约 15 秒,但我想减少查询时间。
编辑: 向 Fields
table 的 UserId
和 IsArchived
列添加了索引。查询执行计划:
** 编辑 2:** 统计数据:
SQL Server parse and compile time:
CPU time = 0 ms, elapsed time = 0 ms.
SQL Server Execution Times:
CPU time = 0 ms, elapsed time = 0 ms.
SQL Server parse and compile time:
CPU time = 0 ms, elapsed time = 0 ms.
SQL Server Execution Times:
CPU time = 0 ms, elapsed time = 0 ms.
SQL Server Execution Times:
CPU time = 0 ms, elapsed time = 0 ms.
SQL Server Execution Times:
CPU time = 0 ms, elapsed time = 0 ms.
(13 row(s) affected)
Table 'FieldSeasonHistory'. Scan count 13, logical reads 26, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'NdviHistory'. Scan count 13, logical reads 26, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'NaturalColorImageHistory'. Scan count 13, logical reads 26, physical reads 0, read-ahead reads 0, lob logical reads 604, lob physical reads 0, lob read-ahead reads 0.
Table 'NdviImageHistory'. Scan count 13, logical reads 39, physical reads 0, read-ahead reads 0, lob logical reads 68, lob physical reads 0, lob read-ahead reads 0.
Table 'WeatherHistory'. Scan count 0, logical reads 39, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Users'. Scan count 0, logical reads 228, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Fields'. Scan count 1, logical reads 19, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
(1 row(s) affected)
SQL Server Execution Times:
CPU time = 15 ms, elapsed time = 16 ms.
SQL Server parse and compile time:
CPU time = 0 ms, elapsed time = 0 ms.
SQL Server Execution Times:
CPU time = 0 ms, elapsed time = 0 ms.
您需要为每个表创建多列索引。索引应该是 where 中的列,order by
中的列,然后是 select
中的列。例如:
NdviImageHistory(FieldId, [Date], [Base64])
NaturalColorImageHistory(FieldId, [Date], [Base64])
- 等等。
像这样更新您的查询。
SELECT Fields.*,
WeatherHistory.TempSumC AS CurrentTempSumC,
TempSumF AS CurrentTempSumF,
PrecipitationSumMm AS CurrentPrecipitationSumMm,
nih.[Base64] AS CurrentNdviImageBase64,
ncih.[Base64] AS CurrentNaturalColorImageBase64,
MeanNdvi AS CurrentMeanNdvi,
IsOpenSeason
FROM Fields
LEFT JOIN WeatherHistory ON FieldId = Id AND [Date] = CAST(GETUTCDATE() AS DATE)
OUTER APPLY
(
SELECT MAX(NdviImageHistory.ID) MAX_ID
FROM NdviImageHistory
WHERE FieldId = Id
) nih_ID
OUTER APPLY
(
SELECT [Base64] FROM NdviImageHistory X WHERE X.ID = nih_ID.MAX_ID
)nih
用户更多外部申请所有这些表 {nih , ncih, nh, fsh } 试试这个。
我只为 [nih] 使用 1 个外层
从 OUTER APPLY Joins 中删除 TOP 1 和 Order by