Ben*_*nCr 2 performance sql-server-2008-r2 query-performance
我有两个数据库,并且都对具有相同索引的同一个表有相同的视图。
该视图从位置表中选择给定 IMEI 的顶部位置。
CREATE VIEW [dbo].[LatestDeviceLocation]
AS
SELECT DISTINCT t.Imei, t.Accuracy, t.UserId, t.Lat, t.Lng, t.Timestamp
FROM (SELECT Imei, MAX(Timestamp) AS latest
FROM dbo.DeviceLocation
GROUP BY Imei) AS m INNER JOIN
dbo.DeviceLocation AS t ON t.Imei = m.Imei AND t.Timestamp = m.latest
GO
Run Code Online (Sandbox Code Playgroud)
我正在使用一个非常简单的 select 查询视图,其中包含一个非常简单的 where 子句。
SELECT TOP 1000 [Imei]
,[Accuracy]
,[UserId]
,[Lat]
,[Lng]
,[Timestamp]
FROM [dbo].[LatestDeviceLocation]
Where [Timestamp] > '2015-02-19T00:00:00.000Z' AND [Timestamp] < '2015-02-26T23:59:59.999Z'
Run Code Online (Sandbox Code Playgroud)
在我的实时服务器上,当我查询我的视图时,我会在 < 1 秒内取回数据。当我添加一个Where [Timestamp] > '2015-02-19T00:00:00.000Z' AND [Timestamp] < '2015-02-26T23:59:59.999Z'
跳转到大约 1 分钟的 where 子句时。
在我的测试服务器上,它有 10 倍多的数据(如果 Imei 编号与实时站点 25 相同,则有 35 万多个位置共享),无论是否使用 where 子句,查询都会在 < 1 秒内返回数据。
我找了锁,没看到。
我重新创建了索引,以防它损坏并且没有区别。
我已经完全删除了索引,性能没有改变。
这是我在两台服务器上使用的索引。
/****** Object: Index [GangHeatMapIndex] Script Date: 02/26/2015 22:38:38 ******/
CREATE NONCLUSTERED INDEX [GangHeatMapIndex] ON [dbo].[DeviceLocation]
(
[UserId] ASC,
[Timestamp] ASC,
[Imei] ASC
)
INCLUDE ( [DeviceLocationId],
[Accuracy],
[Lat],
[Lng]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
Run Code Online (Sandbox Code Playgroud)
编辑:我刚刚意识到我没有在正确的地方寻找锁。它在查询时取出对象锁。我正在尝试解决如何在视图中内置“无锁”的情况下编写我的视图。
编辑2:我附上了执行计划,顶部是索引,底部没有。
编辑 3:更多执行计划,这次全部在实时服务器上,重新添加索引,有和没有 where 子句。
编辑4:
我已将视图更改为使用公用表表达式,如下所示,性能要好得多。
WITH cte
AS (SELECT Rank()
OVER (
partition BY dloc.[Imei]
ORDER BY dloc.[Timestamp], devicelocationid DESC) AS arank,
dloc.*
FROM [dbo].[DeviceLocation] AS dloc)
SELECT [Imei], [Accuracy], [UserId], [Lat], [Lng], [Timestamp]
FROM cte
WHERE arank = 1
Run Code Online (Sandbox Code Playgroud)
通过防止在最终结果中发生任何重复,在订单中包含设备 DeviceLocationId。
编辑- 下面假设查询将返回的行数(如果不存在限制)超过限制。(如......它通常会返回 5000 行,但限制迫使它返回 1000)
任何时候您对查询返回的行数有限制时,您都不应该期望该查询的 TIMING 与性能有任何相关性。
例如,如果您采用这样的简单查询:
SELECT * FROM table_with_1m_rows;
Run Code Online (Sandbox Code Playgroud)
处理需要一段时间,因为它必须通过顺序扫描获取所有行。
如果我将其调整为:
SELECT TOP 1000 * FROM table_with_1m_rows;
Run Code Online (Sandbox Code Playgroud)
它会相对较快地返回,因为虽然它仍然执行顺序扫描,但在超过 1000 行后它可以停止。
如果我然后将其调整为:
SELECT TOP 1000 * FROM table_with_1m_rows WHERE col1 > 100;
Run Code Online (Sandbox Code Playgroud)
它将比之前的查询花费更长的时间,因为虽然它仍然执行顺序扫描,但在返回 1000 行之前很可能必须扫描 1000 多行。
无论数据库需要使用顺序扫描还是索引扫描,以上所有内容都适用。
如果您真的想对查询的性能进行故障排除,则需要删除 TOP 1000,然后查看您的查询计划并查看性能下降的位置...(在这种情况下,很可能缺少有用的索引)