.WRITE 子句性能优化

got*_*tqn 7 varchar sql-server-2012 update

我发现您可以使用子句(示例hereherehigh performance updatesvarchar(max),nvarchar(max),varbinary(max)列进行操作。不幸的是,官方文档中没有提到性能优化。.WRITE

谁能告诉有任何优化吗?有人做过性能测试吗?此外,如果有优化,我想它也只会影响特定情况。

Kin*_*hah 3

WRITE方法是最少记录的。如果您使用常规UPDATE语句,则会导致使用 覆盖整个字符串FULL LOGGING。当处理大量更新时,这会变得低效。

为了支持大值数据类型的更新,UPDATE语法支持.WRITE方法。由于其最小日志记录的性质(包括插入或附加新数据),这将导致较少的事务日志。

注意:如果目标是,则UPDATE使用方法将会失败。WRITELOBNULL

REGULAR UPDATE下面是一个快速而肮脏的重现,显示了使用和UPDATE使用方法生成的事务日志.WRITE

--- create table

create table dbo.testWRITEUpdate (
    ID int identity(1, 1)
    ,COMMENTS varchar(MAX) not null
    )
go

insert into dbo.testWRITEUpdate (COMMENTS)
values (REPLICATE(CAST('KIN' as varchar(max)), 9000))

checkpoint
go
Run Code Online (Sandbox Code Playgroud)

---定期更新:

set statistics io on
 begin tran
update dbo.testWRITEUpdate
set COMMENTS =  STUFF(COMMENTS, 9, 55, '$$$$$(((())))))))))))))____GarbageData____ Entered ____')
where ID  =1

set statistics io off
go

commit tran
Run Code Online (Sandbox Code Playgroud)

-- 统计IO输出

 Table 'testWRITEUpdate'. Scan count 1, logical reads 1, physical reads 0, read-ahead reads 0, lob logical reads 15, lob physical reads 0, lob read-ahead reads 6.
Run Code Online (Sandbox Code Playgroud)

-- 生成事务日志 --> 6 条日志记录,54580 字节

在此输入图像描述

更新使用WRITE方法:

begin tran
set statistics io on
update dbo.testWRITEUpdate
set COMMENTS.WRITE('$$$$$(((())))))))))))))____GarbageData____ Entered ____',9,55)
where ID  =1
set statistics io off

commit tran
go
Run Code Online (Sandbox Code Playgroud)

-- 统计IO

Table 'testWRITEUpdate'. Scan count 1, logical reads 1, physical reads 0, read-ahead reads 0, lob logical reads 1, lob physical reads 0, lob read-ahead reads 0.
Run Code Online (Sandbox Code Playgroud)

-- 生成事务日志 --> 3 条 464 字节的日志记录

在此输入图像描述

上述测试证明该WRITE方法在生成事务日志方面提供了更多好处,因为它是最小日志操作+产生较少的逻辑读取。

注意:这只是表面现象,可以进行更多测试来实际证明 WRITE 方法的性能是否比常规 UPDATE 更好,尤其是在处理 VARCHAR、NVARCHAR 或 VARBINARY 数据类型时。


更新(根据OP的要求):

下面是查找的查询sys.dm_tran_database_transactions

SELECT [database_transaction_log_bytes_used] FROM sys.dm_tran_database_transactions
WHERE [database_id] = DB_ID ('test_kin');
GO
Run Code Online (Sandbox Code Playgroud)

---或更详细的版本:

SELECT DTST.[session_id], 
 DES.[login_name] AS [Login Name], 
 DB_NAME (DTDT.database_id) AS [Database], 
 DTDT.[database_transaction_begin_time] AS [Begin Time], 
 -- DATEDIFF(ms,DTDT.[database_transaction_begin_time], GETDATE()) AS [Duration ms], 
 CASE DTAT.transaction_type 
   WHEN 1 THEN 'Read/write' 
    WHEN 2 THEN 'Read-only' 
    WHEN 3 THEN 'System' 
    WHEN 4 THEN 'Distributed' 
  END AS [Transaction Type], 
  CASE DTAT.transaction_state 
    WHEN 0 THEN 'Not fully initialized' 
    WHEN 1 THEN 'Initialized, not started' 
    WHEN 2 THEN 'Active' 
    WHEN 3 THEN 'Ended' 
    WHEN 4 THEN 'Commit initiated' 
    WHEN 5 THEN 'Prepared, awaiting resolution' 
    WHEN 6 THEN 'Committed' 
    WHEN 7 THEN 'Rolling back' 
    WHEN 8 THEN 'Rolled back' 
  END AS [Transaction State], 
 DTDT.[database_transaction_log_record_count] AS [Log Records], 
 DTDT.[database_transaction_log_bytes_used] AS [Log Bytes Used], 
 DTDT.[database_transaction_log_bytes_reserved] AS [Log Bytes RSVPd], 
 DEST.[text] AS [Last Transaction Text], 
 DEQP.[query_plan] AS [Last Query Plan] 
FROM sys.dm_tran_database_transactions DTDT 
 INNER JOIN sys.dm_tran_session_transactions DTST 
   ON DTST.[transaction_id] = DTDT.[transaction_id] 
 INNER JOIN sys.[dm_tran_active_transactions] DTAT 
   ON DTST.[transaction_id] = DTAT.[transaction_id] 
 INNER JOIN sys.[dm_exec_sessions] DES 
   ON DES.[session_id] = DTST.[session_id] 
 INNER JOIN sys.dm_exec_connections DEC 
   ON DEC.[session_id] = DTST.[session_id] 
 LEFT JOIN sys.dm_exec_requests DER 
   ON DER.[session_id] = DTST.[session_id] 
 CROSS APPLY sys.dm_exec_sql_text (DEC.[most_recent_sql_handle]) AS DEST 
 OUTER APPLY sys.dm_exec_query_plan (DER.[plan_handle]) AS DEQP 
ORDER BY DTDT.[database_transaction_log_bytes_used] DESC;
-- ORDER BY [Duration ms] DESC;
Run Code Online (Sandbox Code Playgroud)