优化我的SQL Server查询
我有一个python应用程序,它ping设备作为测试,以检查它们是否处于活动状态 下面是我用来对每个设备进行分组的查询,并根据该设备的PingResults中的最后一条记录确定该设备是否在线优化我的SQL Server查询,sql,sql-server,sql-server-2008,Sql,Sql Server,Sql Server 2008,我有一个python应用程序,它ping设备作为测试,以检查它们是否处于活动状态 下面是我用来对每个设备进行分组的查询,并根据该设备的PingResults中的最后一条记录确定该设备是否在线 SELECT c.ID, c.DeviceName, c.GroupID, c.DeviceIP, p1.Status, p1.DateTime AS LastUpdate, DeviceGroups.GroupName FROM Devices AS
SELECT
c.ID, c.DeviceName, c.GroupID, c.DeviceIP, p1.Status,
p1.DateTime AS LastUpdate, DeviceGroups.GroupName
FROM
Devices AS c
INNER JOIN
PingResults AS p1 ON c.ID = p1.DeviceID
INNER JOIN
DeviceGroups ON c.GroupID = DeviceGroups.ID
LEFT OUTER JOIN
PingResults AS p2 ON c.ID = p2.DeviceID
AND (p1.DateTime < p2.DateTime OR
p1.DateTime = p2.DateTime AND p1.DeviceID < p2.DeviceID)
WHERE
(p2.ID IS NULL)
当前执行计划
是否有任何方法可以优化或更改此查询以提高效率,因为以当前速度,当数据库填满时,运行此查询将花费太长时间
计划中最大的成本是哈希匹配(内部联接) 为了加快这一速度,请将参与联接的两个表(设备和设备组)索引到它们联接的列上
这会将哈希匹配更改为一个内部循环,这比您在计划中看到的要快得多。计划中最大的成本是哈希匹配(内部连接)
LEFT OUTER JOIN PingResults AS p2
ON c.ID = p2.DeviceID AND (p1.DateTime < p2.DateTime
OR p1.DateTime = p2.DateTime AND p1.DeviceID < p2.DeviceID)
WHERE (p2.ID IS NULL)
为了加快这一速度,请将参与联接的两个表(设备和设备组)索引到它们联接的列上
这将把散列匹配更改为内部循环,这将比您在计划中看到的更快
LEFT OUTER JOIN PingResults AS p2
ON c.ID = p2.DeviceID AND (p1.DateTime < p2.DateTime
OR p1.DateTime = p2.DateTime AND p1.DeviceID < p2.DeviceID)
WHERE (p2.ID IS NULL)
并为每个表创建聚集索引
upd
再看一眼:
SELECT c.ID,
c.DeviceName,
c.GroupID,
c.DeviceIP,
p1.[Status],
p1.LastUpdate,
DeviceGroups.GroupName
FROM Devices AS c
INNER JOIN DeviceGroups
ON c.GroupID = DeviceGroups.ID
CROSS APPLY(
SELECT TOP 1 p1.[Status], p1.[DateTime] AS LastUpdate
FROM PingResults AS p1
WHERE p1.DeviceID = c.ID
ORDER BY p1.DateTime DESC
) p1
无需两次“读取”PingResults
另一件事是:
ON c.ID = p2.DeviceID
AND (p1.DateTime < p2.DateTime
OR p1.DateTime = p2.DateTime
AND p1.DeviceID < p2.DeviceID ---<<<<<<<<<<<<<<<<<<<<
)
c.ID=p2.DeviceID上的
和(p1.DateTime
upd
再看一眼:
SELECT c.ID,
c.DeviceName,
c.GroupID,
c.DeviceIP,
p1.[Status],
p1.LastUpdate,
DeviceGroups.GroupName
FROM Devices AS c
INNER JOIN DeviceGroups
ON c.GroupID = DeviceGroups.ID
CROSS APPLY(
SELECT TOP 1 p1.[Status], p1.[DateTime] AS LastUpdate
FROM PingResults AS p1
WHERE p1.DeviceID = c.ID
ORDER BY p1.DateTime DESC
) p1
无需两次“读取”PingResults
另一件事是:
ON c.ID = p2.DeviceID
AND (p1.DateTime < p2.DateTime
OR p1.DateTime = p2.DateTime
AND p1.DeviceID < p2.DeviceID ---<<<<<<<<<<<<<<<<<<<<
)
c.ID=p2.DeviceID上的
和(p1.DateTime
SELECT c.ID, c.DeviceName, c.GroupID, c.DeviceIP, p1.Status,
p1.DateTime AS LastUpdate, dg.GroupName
FROM Devices c INNER JOIN
PingResults p1
ON c.ID = p1.DeviceID INNER JOIN
DeviceGroups dg
ON c.GroupID = dg.ID LEFT OUTER JOIN
PingResults p2
ON c.ID = p2.DeviceID AND
(p1.DateTime < p2.DateTime OR
p1.DateTime = p2.DateTime AND p1.DeviceID < p2.DeviceID
)
WHERE p2.ID IS NULL;
对于此查询:
SELECT c.ID, c.DeviceName, c.GroupID, c.DeviceIP, p1.Status,
p1.DateTime AS LastUpdate, dg.GroupName
FROM Devices c INNER JOIN
PingResults p1
ON c.ID = p1.DeviceID INNER JOIN
DeviceGroups dg
ON c.GroupID = dg.ID LEFT OUTER JOIN
PingResults p2
ON c.ID = p2.DeviceID AND
(p1.DateTime < p2.DateTime OR
p1.DateTime = p2.DateTime AND p1.DeviceID < p2.DeviceID
)
WHERE p2.ID IS NULL;
在我看来,您应该使用行号:
;WITH CTE as
(
SELECT
c.ID,
c.DeviceName,
c.GroupID,
c.DeviceIP,
p1.Status,
p1.DateTime,
DeviceGroups.GroupName,
row_number() over (partition by c.ID order by p1.DateTime desc) rn
FROM
Devices AS c
INNER JOIN
PingResults AS p1
ON c.ID = p1.DeviceID
INNER JOIN
DeviceGroups
ON c.GroupID = DeviceGroups.ID
)
SELECT
ID,
DeviceName,
GroupID,
DeviceIP,
Status,
DateTime LastUpdate,
DeviceGroups.GroupName
FROM CTE
WHERE rn = 1
在我看来,您应该使用行号:
;WITH CTE as
(
SELECT
c.ID,
c.DeviceName,
c.GroupID,
c.DeviceIP,
p1.Status,
p1.DateTime,
DeviceGroups.GroupName,
row_number() over (partition by c.ID order by p1.DateTime desc) rn
FROM
Devices AS c
INNER JOIN
PingResults AS p1
ON c.ID = p1.DeviceID
INNER JOIN
DeviceGroups
ON c.GroupID = DeviceGroups.ID
)
SELECT
ID,
DeviceName,
GroupID,
DeviceIP,
Status,
DateTime LastUpdate,
DeviceGroups.GroupName
FROM CTE
WHERE rn = 1
嗨,谢谢你的帮助,排号()版本使查询在不到1的时间内运行second@joshkirkpatrick…在这种情况下,我很惊讶你没有接受这个答案。另一个人也给出了一个即时的答案,他首先回答,如果可以的话,我会同时接受这两个答案。@Josh Kirkpatrick…那很好。你有一个很好的理由,交叉应用
解决方案(显然)。嗨,谢谢你的帮助,排号()版本使查询在不到1的时间内运行second@joshkirkpatrick…在这种情况下,我很惊讶你没有接受这个答案。另一个人也给出了一个即时的答案,他首先回答,如果可以的话,我会同时接受这两个答案。@Josh Kirkpatrick…那很好。你有一个很好的理由,交叉应用
解决方案(显然).您好,谢谢您的帮助!您所做的第一次更改使其在大约4秒的执行时间内完成,第二次更改使其几乎瞬间完成。不要忘记为每个表创建聚集索引。您好,谢谢您的帮助!您所做的第一次更改使其在大约4秒的执行时间内完成,第二次更改使其几乎瞬间完成。不要忘记创建聚集索引每一张桌子。