我有一个运行 6 分钟的 T-SQL 查询。
其中同一个表有多个子查询。我认为这是问题的原因。 但我不知道如何优化它。
SELECT dateheure, bac, presence, reponse
,(select top 1 dateheure from LogEvents where bac = t1.bac and dateheure < t1.dateheure order by id desc) as dateheure_precedente
,(select top 1 presence from LogEvents where bac = t1.bac and dateheure < t1.dateheure order by id desc) as presence_precedente
,(select top 1 reponse from LogEvents where bac = t1.bac and dateheure < t1.dateheure order by id desc) as reponse_precedente
,(select top 1 dateheure from LogEvents where bac = t1.bac and dateheure > t1.dateheure order by id asc) as dateheure_suivante
,(select top 1 presence from LogEvents where bac = t1.bac and dateheure > t1.dateheure order by id asc) as presence_suivante
,(select top 1 reponse from LogEvents where bac = t1.bac and dateheure > t1.dateheure order by id asc) as reponse_suivante
FROM [alpla_log].[dbo].[LogEvents] t1
WHERE
t1.presence = 7845
AND dateheure BETWEEN '11/07/2024 00:00:00' AND '11/07/2024 23:59:59.997'
ORDER BY id DESC
唯一使用的表是“LogEvents”
CREATE TABLE LogEvents (
id int IDENTITY NOT NULL PRIMARY KEY,
dateheure datetime NULL,
type varchar(50) NULL,
msg varchar(MAX) NULL,
presence int NULL,
destination int NULL,
status_prt int NULL,
reponse int NULL,
bac int NULL
);
您可以在这里找到执行计划。
我尝试在表上添加索引,但没有什么区别。
CREATE NONCLUSTERED INDEX ON dbo.Logevents (bac, dateheure) INCLUDE (reponse)
没有其他索引。
该表是自动化仓库中的事件日志。它保存了盒子在不同地方的位置。我想找到每个盒子与特定位置相比的上一个和下一个位置。
您的查询可以得到显着改善。
APPLY
替换六个子查询,但更好的解决方案是使用 LEAD
和 LAG
窗口函数。WHERE
子句不是“可管理的”(不能使用索引)。相反,使用日期范围,最好是半开区间 >= AND <
ORDER BY
,因为它与 WHERE
和 PARTITION BY
的 LEAD
的顺序不同。SELECT
dateheure,
bac,
presence,
reponse,
LAG(t1.dateheure) OVER (PARTITION BY t1.bac ORDER BY t1.dateheure) as dateheure_precedente,
LAG(t1.presence ) OVER (PARTITION BY t1.bac ORDER BY t1.dateheure) as presence_precedente,
LAG(t1.reponse ) OVER (PARTITION BY t1.bac ORDER BY t1.dateheure) as reponse_precedente,
LEAD(t1.dateheure) OVER (PARTITION BY t1.bac ORDER BY t1.dateheure) as dateheure_suivante,
LEAD(t1.presence ) OVER (PARTITION BY t1.bac ORDER BY t1.dateheure) as presence_suivante,
LEAD(t1.reponse ) OVER (PARTITION BY t1.bac ORDER BY t1.dateheure) as reponse_suivante
FROM LogEvents t1
WHERE
t1.presence = 7845
AND dateheure >= '20240711'
AND dateheure < '20240712';
最后添加正确的索引来支持此查询。
CREATE INDEX IX ON LogEvents (presence, bac, dateheure) INCLUDE (reponse);
您可以从这个小提琴中看到,这现在会导致基表的单次扫描,没有连接,没有键查找,也没有排序。