数据检索性能
Data retrieval performance
使用 SSMS 或 Azure 数据工作室,我可以在 2 毫秒内将 50 万行插入临时文件 table,但从 table 或临时文件 table 中检索要筛选的行需要 13 到 15 秒。我不确定接下来要在哪里查看性能丢失的地方,因为这不是几个月前发布的问题。
这是一个生产服务器,已经 运行 几个月了 SQL 2017。无论我是在客户端上还是直接在服务器上,但在具有标准的基本 PC 上,都会发生这种情况磁盘和仅 8 GB 的 RAM 最多快三倍
SELECT SML.CONTACT_Id
INTO ##slr
FROM dbo.Stage_MailingLists AS SML;
SELECT *
FROM ##slr AS S;
DROP TABLE ##slr;
SQL Server parse and compile time:
CPU time = 0 ms, elapsed time = 0 ms.
SQL Server Execution Times:
CPU time = 0 ms, elapsed time = 0 ms.
SQL Server parse and compile time:
CPU time = 0 ms, elapsed time = 2 ms.
Table 'Stage_MailingLists'. Scan count 9, logical reads 13482, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
(521001 rows affected)
(1 row affected)
SQL Server Execution Times:
CPU time = 1187 ms, elapsed time = 365 ms.
SQL Server parse and compile time:
CPU time = 0 ms, elapsed time = 0 ms.
(521001 rows affected)
Table '##slr'. Scan count 1, logical reads 1493, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
(1 row affected)
SQL Server Execution Times:
CPU time = 329 ms, elapsed time = 8296 ms.
SQL Server parse and compile time:
CPU time = 0 ms, elapsed time = 0 ms.
SQL Server Execution Times:
CPU time = 0 ms, elapsed time = 0 ms.
插入数据和显示数据是很不一样的。当您执行 INSERT
时,没有数据返回给客户端,所有内容都包含在实例中。应用程序也不需要解释返回的数据集并将其转换为显示。
当您使用 SELECT
时,要显示数据,该数据需要从实例发送到客户端;如果该客户端是远程主机,那么网络 speed/traffic 之类的东西可能是大型数据集的重要因素(这里有 50 万行,这是一个不错的显示量)。应用程序还需要解释来自实例的数据并将其转换为可显示的格式;在可能将其转换为数据网格的 SSMS 中。如果您正在限制客户端,那么您也可能会减慢查询速度,因为数据需要加载到应用程序的内存池中并进行处理才能显示。
SELECT
和 INSERT
的速度,尤其是对于大型数据集,可能无法比较,因为它们的操作完全不同。
事实证明,Sophos 防病毒软件有一个更新 'pending restart' 导致瓶颈重新启动服务器并全部恢复到预期的基线。
由于您在 SQL 2017 年,您可以使用会话等待统计信息来衡量引擎等待查询的时间。 EG在Master中安装一个程序如:
use master
go
create or alter procedure sp_exec_with_time_and_wait_stats @sql nvarchar(max)
as
begin
set nocount on;
with q as
(
select *
from sys.dm_exec_session_wait_stats
where session_id = @@spid
union all
select @@spid session_id, 'CPU_TIME', 0,cpu wait_time_ms,0,0
from sysprocesses where spid = @@spid
)
select *
into #waits
from q
print ('-------begin batch--------')
print ( @sql )
print ('--------end batch---------')
set statistics io on;
set statistics time on;
exec ( @sql );
set statistics io off;
set statistics time off;
declare c cursor local for
with n as
(
select *
from sys.dm_exec_session_wait_stats
where session_id = @@spid
union all
select @@spid session_id, 'CPU_TIME', 0,cpu cpu_time,0,0
from sysprocesses where spid = @@spid
)
select n.wait_type,
n.waiting_tasks_count - coalesce(p.waiting_tasks_count,0) waiting_tasks_count,
n.wait_time_ms - coalesce(p.wait_time_ms,0) wait_time_ms,
case when n.max_wait_time_ms > coalesce(p.max_wait_time_ms,0) then n.max_wait_time_ms else null end max_wait_time,
n.signal_wait_time_ms - coalesce(p.signal_wait_time_ms,0) signal_wait_time
from n
left join #waits p
on p.wait_type = n.wait_type
where n.session_id = @@spid
and n.wait_time_ms > coalesce(p.wait_time_ms,0)
order by n.wait_time_ms - coalesce(p.wait_time_ms,0) desc;
declare @wait_type nvarchar(60),
@waiting_tasks_count bigint,
@wait_time_ms bigint,
@max_wait_time_ms bigint,
@signal_wait_time_ms bigint
print (
'
SQL Server Wait Times (with CPU):
wait_type waiting_tasks_count wait_time_ms max_wait_time signal_wait_time')
print (
' ------------------------------------------------------------ -------------------- --------------------- ------------------ --------------------')
open c
fetch next from c into @wait_type, @waiting_tasks_count, @wait_time_ms, @max_wait_time_ms, @signal_wait_time_ms
while @@FETCH_STATUS = 0
begin
declare @line nvarchar(2000) = N''
declare @val nvarchar(60) = @wait_type
declare @len int = 45
set @line = concat(@line,left(concat(@val, space(@len)),@len))
set @len = 20
set @val = str(@waiting_tasks_count)
set @line = concat(@line,right(concat(space(@len),@val),@len))
set @val = str(@wait_time_ms)
set @line = concat(@line,right(concat(space(@len),@val),@len))
set @val = str(coalesce(@max_wait_time_ms,''))
set @line = concat(@line,right(concat(space(@len),@val),@len))
set @val = str(@signal_wait_time_ms)
set @line = concat(@line,right(concat(space(@len),@val),@len))
print (' ' + @line)
fetch next from c into @wait_type, @waiting_tasks_count, @wait_time_ms, @max_wait_time_ms, @signal_wait_time_ms
end
close c
deallocate c
print ('')
end
然后从你的数据库中
use AdventureWorksDW2017
go
declare @sql nvarchar(max) = 'select top 1000000 * into #x from factInternetSales order by 1,2,5;'
exec sp_exec_with_time_and_wait_stats @sql
这将打印您的 IO,CPU 和等待统计信息,例如:
-------begin batch--------
select top 1000000 * into #x from factInternetSales order by 1,2,5;
--------end batch---------
SQL Server parse and compile time:
CPU time = 0 ms, elapsed time = 12 ms.
Table 'FactInternetSales'. Scan count 9, logical reads 1260, physical reads 0, read-ahead reads 1260, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 1057, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
SQL Server Execution Times:
CPU time = 435 ms, elapsed time = 335 ms.
SQL Server Execution Times:
CPU time = 435 ms, elapsed time = 349 ms.
SQL Server Execution Times:
CPU time = 0 ms, elapsed time = 0 ms.
SQL Server Wait Times (with CPU):
wait_type waiting_tasks_count wait_time_ms max_wait_time signal_wait_time
------------------------------------------------------------ -------------------- --------------------- ------------------ --------------------
LATCH_EX 4879 572 0 69
CPU_TIME 0 435 0 0
CXPACKET 22 331 0 0
PAGEIOLATCH_SH 26 10 0 0
PAGELATCH_SH 17 6 0 1
PAGELATCH_UP 74 6 0 1
LCK_M_S 9 3 0 0
CXROWSET_SYNC 8 2 0 0
MEMORY_ALLOCATION_EXT 601 1 0 0
SESSION_WAIT_STATS_CHILDREN 11 1 0 1
LATCH_SH 3 1 0 0
使用 SSMS 或 Azure 数据工作室,我可以在 2 毫秒内将 50 万行插入临时文件 table,但从 table 或临时文件 table 中检索要筛选的行需要 13 到 15 秒。我不确定接下来要在哪里查看性能丢失的地方,因为这不是几个月前发布的问题。
这是一个生产服务器,已经 运行 几个月了 SQL 2017。无论我是在客户端上还是直接在服务器上,但在具有标准的基本 PC 上,都会发生这种情况磁盘和仅 8 GB 的 RAM 最多快三倍
SELECT SML.CONTACT_Id
INTO ##slr
FROM dbo.Stage_MailingLists AS SML;
SELECT *
FROM ##slr AS S;
DROP TABLE ##slr;
SQL Server parse and compile time:
CPU time = 0 ms, elapsed time = 0 ms.
SQL Server Execution Times:
CPU time = 0 ms, elapsed time = 0 ms.
SQL Server parse and compile time:
CPU time = 0 ms, elapsed time = 2 ms.
Table 'Stage_MailingLists'. Scan count 9, logical reads 13482, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
(521001 rows affected)
(1 row affected)
SQL Server Execution Times:
CPU time = 1187 ms, elapsed time = 365 ms.
SQL Server parse and compile time:
CPU time = 0 ms, elapsed time = 0 ms.
(521001 rows affected)
Table '##slr'. Scan count 1, logical reads 1493, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
(1 row affected)
SQL Server Execution Times:
CPU time = 329 ms, elapsed time = 8296 ms.
SQL Server parse and compile time:
CPU time = 0 ms, elapsed time = 0 ms.
SQL Server Execution Times:
CPU time = 0 ms, elapsed time = 0 ms.
插入数据和显示数据是很不一样的。当您执行 INSERT
时,没有数据返回给客户端,所有内容都包含在实例中。应用程序也不需要解释返回的数据集并将其转换为显示。
当您使用 SELECT
时,要显示数据,该数据需要从实例发送到客户端;如果该客户端是远程主机,那么网络 speed/traffic 之类的东西可能是大型数据集的重要因素(这里有 50 万行,这是一个不错的显示量)。应用程序还需要解释来自实例的数据并将其转换为可显示的格式;在可能将其转换为数据网格的 SSMS 中。如果您正在限制客户端,那么您也可能会减慢查询速度,因为数据需要加载到应用程序的内存池中并进行处理才能显示。
SELECT
和 INSERT
的速度,尤其是对于大型数据集,可能无法比较,因为它们的操作完全不同。
事实证明,Sophos 防病毒软件有一个更新 'pending restart' 导致瓶颈重新启动服务器并全部恢复到预期的基线。
由于您在 SQL 2017 年,您可以使用会话等待统计信息来衡量引擎等待查询的时间。 EG在Master中安装一个程序如:
use master
go
create or alter procedure sp_exec_with_time_and_wait_stats @sql nvarchar(max)
as
begin
set nocount on;
with q as
(
select *
from sys.dm_exec_session_wait_stats
where session_id = @@spid
union all
select @@spid session_id, 'CPU_TIME', 0,cpu wait_time_ms,0,0
from sysprocesses where spid = @@spid
)
select *
into #waits
from q
print ('-------begin batch--------')
print ( @sql )
print ('--------end batch---------')
set statistics io on;
set statistics time on;
exec ( @sql );
set statistics io off;
set statistics time off;
declare c cursor local for
with n as
(
select *
from sys.dm_exec_session_wait_stats
where session_id = @@spid
union all
select @@spid session_id, 'CPU_TIME', 0,cpu cpu_time,0,0
from sysprocesses where spid = @@spid
)
select n.wait_type,
n.waiting_tasks_count - coalesce(p.waiting_tasks_count,0) waiting_tasks_count,
n.wait_time_ms - coalesce(p.wait_time_ms,0) wait_time_ms,
case when n.max_wait_time_ms > coalesce(p.max_wait_time_ms,0) then n.max_wait_time_ms else null end max_wait_time,
n.signal_wait_time_ms - coalesce(p.signal_wait_time_ms,0) signal_wait_time
from n
left join #waits p
on p.wait_type = n.wait_type
where n.session_id = @@spid
and n.wait_time_ms > coalesce(p.wait_time_ms,0)
order by n.wait_time_ms - coalesce(p.wait_time_ms,0) desc;
declare @wait_type nvarchar(60),
@waiting_tasks_count bigint,
@wait_time_ms bigint,
@max_wait_time_ms bigint,
@signal_wait_time_ms bigint
print (
'
SQL Server Wait Times (with CPU):
wait_type waiting_tasks_count wait_time_ms max_wait_time signal_wait_time')
print (
' ------------------------------------------------------------ -------------------- --------------------- ------------------ --------------------')
open c
fetch next from c into @wait_type, @waiting_tasks_count, @wait_time_ms, @max_wait_time_ms, @signal_wait_time_ms
while @@FETCH_STATUS = 0
begin
declare @line nvarchar(2000) = N''
declare @val nvarchar(60) = @wait_type
declare @len int = 45
set @line = concat(@line,left(concat(@val, space(@len)),@len))
set @len = 20
set @val = str(@waiting_tasks_count)
set @line = concat(@line,right(concat(space(@len),@val),@len))
set @val = str(@wait_time_ms)
set @line = concat(@line,right(concat(space(@len),@val),@len))
set @val = str(coalesce(@max_wait_time_ms,''))
set @line = concat(@line,right(concat(space(@len),@val),@len))
set @val = str(@signal_wait_time_ms)
set @line = concat(@line,right(concat(space(@len),@val),@len))
print (' ' + @line)
fetch next from c into @wait_type, @waiting_tasks_count, @wait_time_ms, @max_wait_time_ms, @signal_wait_time_ms
end
close c
deallocate c
print ('')
end
然后从你的数据库中
use AdventureWorksDW2017
go
declare @sql nvarchar(max) = 'select top 1000000 * into #x from factInternetSales order by 1,2,5;'
exec sp_exec_with_time_and_wait_stats @sql
这将打印您的 IO,CPU 和等待统计信息,例如:
-------begin batch--------
select top 1000000 * into #x from factInternetSales order by 1,2,5;
--------end batch---------
SQL Server parse and compile time:
CPU time = 0 ms, elapsed time = 12 ms.
Table 'FactInternetSales'. Scan count 9, logical reads 1260, physical reads 0, read-ahead reads 1260, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 1057, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
SQL Server Execution Times:
CPU time = 435 ms, elapsed time = 335 ms.
SQL Server Execution Times:
CPU time = 435 ms, elapsed time = 349 ms.
SQL Server Execution Times:
CPU time = 0 ms, elapsed time = 0 ms.
SQL Server Wait Times (with CPU):
wait_type waiting_tasks_count wait_time_ms max_wait_time signal_wait_time
------------------------------------------------------------ -------------------- --------------------- ------------------ --------------------
LATCH_EX 4879 572 0 69
CPU_TIME 0 435 0 0
CXPACKET 22 331 0 0
PAGEIOLATCH_SH 26 10 0 0
PAGELATCH_SH 17 6 0 1
PAGELATCH_UP 74 6 0 1
LCK_M_S 9 3 0 0
CXROWSET_SYNC 8 2 0 0
MEMORY_ALLOCATION_EXT 601 1 0 0
SESSION_WAIT_STATS_CHILDREN 11 1 0 1
LATCH_SH 3 1 0 0