查询执行时间不一致

IT *_*her 3 performance index sql-server-2008-r2 query-performance

我有一个查询有时需要很长时间才能执行。当我检查速度时,它需要 15 秒。但实际上它应该运行得更快。当我再次检查查询时,它在 11 秒内再次执行。然后我尝试删除在查询中使用的强制转换和执行时它只在 8 秒内运行。但是当我再次执行原始查询时,它花费的时间更少。我检查了几台运行查询的计算机。但在某些情况下,我也只在 1 或 2 秒内得到输出。所以执行时间不一致。所以我无法找到为什么会发生这种情况?

下面是我用来测试的查询

SELECT [customer].[Customer name],[customer].[Sl_No],[customer].[Id]
FROM [company].dbo.[customer]
WHERE ( Charindex('9000413237',CAST([company].dbo.[customer].[Phone no] AS VARCHAR(MAX)))>0 ) 
Run Code Online (Sandbox Code Playgroud)

这里的客户表大约有 30 列。其中“客户名称”的数据类型为 varchar(255),“Sl_No”的类型为 int,“Id”的类型为 int,“电话号码”的类型为 varchar(255)。

当我执行相同的查询(使用强制转换)时,即使在同一台 PC 上进行不同的试验,执行所需的时间也不同。它从 1 秒到 14 秒不等(我尝试了执行查询的试验次数)。时间的变化可能是由于网络延迟、缓存、其他用户使用率高的表等。但是有什么工具或方法可以让我找到执行时间(可能慢或快)的原因?

更新 我只是尝试使用查询来检查 IO 停顿

SELECT 
    mf.physical_name,
    ( io_stall_read_ms / ( 1.0 + num_of_reads )) as [avg read wait],
    ( io_stall_write_ms / ( 1.0 + num_of_writes )) as [avg write wait],
    i.name,
    fs.io_stall
    FROM    sys.dm_io_virtual_file_stats(NULL, NULL) AS fs
    INNER JOIN sys.master_files AS mf ON fs.database_id = mf.database_id AND fs.[file_id] = mf.[file_id]
    INNER JOIN sys.databases as i on fs.database_id = i.database_id
order by i.name desc
Run Code Online (Sandbox Code Playgroud)

在输出中,我的数据库“公司”占用了高 io 停顿。以下是我为该数据库获得的值。(原始输出包含所有数据库文件的 iostall)

avg read wait-37.17162364 avg write wait -20.66666667 io_stall-4813081 所以我在查询中使用的数据库有很高的iostall。这是什么原因?

我添加了电话号码作为非聚集索引,只是将查询重写为

SELECT [customer].[Customer name],[customer].[Sl_No],[customer].[Id]
 FROM [company].dbo.[customer]
  WHERE [company].dbo.[customer].[Phone no]  LIKE '%9000413237%'
Run Code Online (Sandbox Code Playgroud)

现在查询在 1 秒内执行。我不能使用 LIKE '9000413237%',因为我需要在列的任何部分搜索电话号码。所以我必须使用 LIKE '%9000413237%'。但在几篇文章中提到使用 like '%abc%'不会有利于索引,只有 'abc%' 可以从索引中受益。但在我的情况下,使用 LIKE '%9000413237%' 对我的索引帮助很大。所以我怀疑为什么人们说使用 LIKE '%9000413237%' 没有好处

Cra*_*ein 6

一种可能的解释:

第一次运行查询时,它可能不在缓存中,这意味着它必须从磁盘读取并存储在内存中。如果您的查询保持不变并且执行计划没有改变,则执行相同查询所需的时间将会更少。

如果您使用的 SQL Server 在您自己的计算机上和/或其他人不会受到影响,您可以使用DBCC FREEPROCCACHE清除计划缓存以查看执行时间是否保持不变。

您可以通过运行以下命令来查看缓存中的查询

SELECT text,objtype, refcounts, usecounts, size_in_bytes,
    disk_ios_count, context_switches_count, pages_allocated_count, original_cost,
    current_cost
FROM sys.dm_exec_cached_plans p
    CROSS APPLY sys.dm_exec_sql_text(plan_handle)
    JOIN sys.dm_os_memory_cache_entries e
    ON p.memory_object_address = e.memory_object_address
WHERE cacheobjtype = 'Compiled Plan'
ORDER BY objtype desc, usecounts DESC
Run Code Online (Sandbox Code Playgroud)

如果您看到查询

SELECT [customer].[Customer name],[customer].[Sl_No],[customer].[Id]
FROM [company].dbo.[customer]
WHERE ( Charindex('9000413237',CAST([company].dbo.[customer].[Phone no] AS VARCHAR(MAX)))>0 ) 
Run Code Online (Sandbox Code Playgroud)

然后你知道它在缓存中。

如果清除缓存不能使执行时间更加一致,请在执行查询之前通过选择 CTRL+M 来包含实际的执行计划。

另一种可能的解释: 由于您在不同的计算机上进行测试,因此当 SQL Server 将数据发送回您正在测试的计算机时,可能会涉及额外的网络延迟。您可以通过使用任务管理器并在从另一台服务器运行查询时打开网络选项卡来验证这一点。

更新 15:26

如果带宽是一个问题,一个解决方案是找出: 1. 您的客户端和服务器之间存在多少带宽 2. 您实际使用了多少带宽

您的网络管理员或系统管理员可以告诉您您与域内其他机器之间存在多少带宽。使用Process Explorer或 perfmon,您可以轻松确定 SQL Server 和其他进程使用了​​多少带宽。请记住,当您在服务器上执行查询时,结果不必像远程客户端那样通过网络电缆传输,这会改变执行时间。

不过,您最初的问题是为什么您会看到同一查询的执行时间不一致。所以关于网络和带宽的讨论将是题外话。

更新 09:27

以下是 Process Explorer 的两个屏幕截图,可帮助您找到可让您分析 CPU、IO、内存和网络流量的图表。

主屏幕

主屏幕

图表

图表