选择到临时表中通常比选择到实际表中更快吗?

J.D*_*.D. 35 sql-server memory tempdb temporary-tables sql-server-2016

我想我曾经在某处读到过写入 tempdb 比不在 tempdb 中的实际表更快。这在任何情况下都是真的吗?我想我记得它说了一些关于 tempdb 并将数据存储在内存中的特殊内容?

Dav*_*oft 55

写入 tempdb 比不在 tempdb 中的实际表更快

这是真的。TempDb 中有两个 IO 增强。

写入用户数据库中的表必须在提交时将其日志记录刷新到磁盘,或者如果最少记录的插入(如 SELECT ... INTO),则必须在提交时将数据库页面刷新到磁盘。最小日志记录在用户数据库中的工作方式是将数据库页面直接写入磁盘。到 SELECT ... INTO 完成时,新页面已全部写入物理文件。

TempDb 写入不必在提交时刷新到磁盘,因为 TempDb 在失败后永远不会恢复。所以他们根本不是。您的更改会生成日志记录,但日志缓冲区仅在已满时才会刷新到磁盘,而不是每次提交时。

而且,因为SQL服务器2014在tempdb中最小日志记录插入并不总是写入磁盘无论是。如果您加载一个小的、短暂的临时表,它可能永远不会写入磁盘。日志将有一些关于表的页面分配和元数据条目的记录,但仅此而已。

EG 在 tempdb、完整恢复数据库和简单恢复数据库中运行以下批处理以查看差异。

drop table if exists foo
go
declare @data bigint
declare @log bigint 
select @log = sum(case when type_desc = 'LOG' then num_of_bytes_written end) 
      ,@data =  sum(case when type_desc = 'ROWS' then num_of_bytes_written end) 
from sys.database_files f
cross apply sys.dm_io_virtual_file_stats(db_id(),f.file_id) fs

select * 
into foo
from sys.objects 

select -@log + sum(case when type_desc = 'LOG' then num_of_bytes_written end)  log_bytes
      ,-@data +  sum(case when type_desc = 'ROWS' then num_of_bytes_written end) data_bytes
      , (select recovery_model_desc from sys.databases where database_id = db_id()) recovery_model
from sys.database_files f
cross apply sys.dm_io_virtual_file_stats(db_id(),f.file_id) fs
Run Code Online (Sandbox Code Playgroud)

你会看到类似的东西:

对于简单恢复:

log_bytes            data_bytes           recovery_model
-------------------- -------------------- ---------------
24576                16384                SIMPLE
Run Code Online (Sandbox Code Playgroud)

完全恢复:

log_bytes            data_bytes           recovery_model
-------------------- -------------------- ---------------
36864                0                    FULL
Run Code Online (Sandbox Code Playgroud)

对于 tempdb:

log_bytes            data_bytes           recovery_model
-------------------- -------------------- ---------------
0                    0                    SIMPLE
Run Code Online (Sandbox Code Playgroud)

有时对于 tempdb,您会看到日志缓冲区已刷新:

log_bytes            data_bytes           recovery_model
-------------------- -------------------- ---------------
61440                0                    SIMPLE
Run Code Online (Sandbox Code Playgroud)

  • 有一种情况,初始插入速度更快,但稍后又回来咬你。此演示显示了将数据带入缓冲区缓存的查询需要更长的时间,因为惰性写入器正忙于写入磁盘 tempdb 页面,这些页面对于不再存在的临时表而言是脏的 https://www.youtube.com/watch?v =X60ipwYv1Ms&feature=youtu.be (3认同)

Dav*_*ett 8

除了对 tempdb 的写入之外,通常不是每个命中磁盘/网络 IO,正如David Browne 的回答中所扩展的那样,根据您的 IO 配置,您可能会发现即使数据大到必须被假脱机到磁盘,它仍然更快比选择“普通”表:

  • TempDB 可能位于不同的驱动器上,因此有自己的 IO 带宽。这对于旋转驱动器而不是 SSD 尤其重要。读取写入同一个数据库(或同一个驱动器上的另一个数据库)将涉及更多的磁头移动,这会增加更多的 IO 延迟并可能限制您的有效 IO 带宽。在不同驱动器/阵列上的数据库之间复制数据不会有相同的额外延迟。

  • TempDB 甚至可能位于比主存储更快的媒体上。也许在主存储在网络上的本地驱动器上,或者在主存储在传统驱动器上的 NVMe SSD 上。

如果您使用多个文件组在不同的驱动器/阵列之间传播部分数据,则在同一数据库中也可能会看到这两种差异。

如果您有多个正在使用的数据库,情况也可能相反。由于 TempDB 是共享资源,它以及承载它的驱动器/网络可能比任何单个数据库的数据文件承受更多的负载。