3

我有以下查询:

SELECT
  tl.*, d.*
FROM
  TrackerLocations AS tl
  inner join Trackers t on tl.TrackerId = t.TrackerId
  inner join Devices d on t.UserId = d.UserId
WHERE
  tl.ReceivedTime = (SELECT MAX(tl2.ReceivedTime) FROM TrackerLocations tl2 WHERE tl2.TrackerId = tl.TrackerId)
  and tl.ReceivedTime >= DATEADD (MINUTE,-2,GETUTCDATE())
  and d.OSType <> 3
  and d.Notify = 1

...令我惊讶的是,它不会在可接受的时间内返回结果。我第一次在生产环境中运行它,就像执行了 3 秒。现在,它一直运行到超时(在 C# 应用程序内,30 秒)。
主要目的是:“向我提供任何跟踪器的最新位置以及有关其用户设备的信息,向后看 2 分钟”。
有关优化此查询的任何提示?

谢谢!

索引: Anywhere but where 子句列(ReceivedTime、OSType、Notify)。

关于执行计划,这是一件大事,我不太熟悉。我应该把它贴在这里吗?:)

4

5 回答 5

3
SELECT tl.*,d.*
 FROM
    TrackerLocations AS tl
    inner join Trackers t on tl.TrackerId = t.TrackerId
    inner join Devices d on t.UserId = d.UserId
 WHERE
    tl.ReceivedTime = (SELECT MAX(tl2.ReceivedTime) 
                         FROM TrackerLocations tl2 
                        WHERE tl2.TrackerId = tl.TrackerId 
                          and tl2.ReceivedTime >= @searchTerm)
    and d.RegistrationId <> ''
    and d.OSType <> 3
    and d.Notify = 1
于 2013-08-09T19:52:09.493 回答
2

我建议在 ( TrackerId, ReceivedTime) 上尝试索引,也许也ReceivedTime一样。但是,如果没有分析和实际的执行计划,这只是在黑暗中拍摄。

于 2013-08-09T17:49:44.163 回答
1

TrackerLocations.TrackerId在和上创建索引Trackers.TrackerId。还有第二Devices.UserId次。最后,看看为子句创建索引。Trackers.UserIdJOINTrackerLocations.ReceivedTimeWHERE

通常,优化此类查询的第一个地方是检查您的连接条件是否有索引。此外,如果您有某种过滤器(WHERE子句),那可能是另一个添加索引的地方。

如果不查看查询执行计划,很难准确地说出需要优化的地方。许多因素可以影响它,包括每个表中有多少记录。不过,不要太疯狂地创建索引——它们会影响性能,例如在插入新数据时。最好的建议是只用不同的索引进行测试,看看执行计划是否会给你一些提示。

于 2013-08-09T17:51:10.847 回答
1

因为我不知道这个查询的执行计划是什么样的,所以我只能继续我认为有助于加快结果的方法。

  1. 你有主键和外键约束吗
  2. 这些键是否被索引

除此之外,我会尝试使用 CTE 将结果限制在一起,以达到(未测试)的效果:

;WITH cte_loc AS
(
    SELECT
        tl.*
    FROM
        TrackerLocations tl            
    WHERE
        tl.ReceivedTime >= DATEADD (MINUTE,-2,GETUTCDATE())
),cte_loc2 AS
(
    SELECT
        TrackerId
        ,MAX(ReceivedTime) AS MaxReceivedTime
    FROM
        cte_loc
    GROUP BY
        TrackerId
),cte_dev AS
(
    SELECT
        tl.TrackerId,
        d.*
    FROM
        cte_loc2 tl 
            INNER JOIN Trackers t ON tl.TrackerId = t.TrackerId
            INNER JOIN Devices d ON t.UserId = d.UserId             
    WHERE
        d.OSType <> 3 AND d.Notify = 1
)

SELECT
    tl.*, d.*
FROM
    cte_loc AS tl      
        INNER JOIN cte_loc2 tl2 ON tl.TrackerId = tl2.TrackerId
                               AND tl.ReceivedTime = tl2.MaxReceivedTime
        LEFT JOIN cte_dev d ON tl.TrackerId = d.TrackerId
于 2013-08-09T18:09:38.417 回答
1

由于您要查找最近 2 分钟内的最新 ReceivedTime,因此您需要按ReceivedTimeDESC 顺序创建索引。DESC 顺序部分很重要。它还有助于 MAX 功能。您也可以尝试在(ReceivedTime DESC, TrackerID).

于 2013-08-09T18:23:59.520 回答