微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

sql-server – 为什么SELECT查询会导致写入?

我注意到在运行sql Server 2016 SP1 CU6的服务器上,有时扩展事件会话会显示导致写入的SELECT查询.
例如:

执行计划没有显示写入的明显原因,例如可能溢出到TempDB的哈希表,假脱机或排序:

对MAX类型或自动统计信息更新的变量赋值也可能导致这种情况,但在这种情况下写入的原因都不是.

写作还能从中得到什么?

解决方法

在某些情况下,Query Store可能导致写入作为select语句的效果发生,并且在同一会话中.

这可以复制如下:

USE master;
GO
CREATE DATABASE [Foo];
ALTER DATABASE [Foo] SET QUERY_STORE (OPERATION_MODE = READ_WRITE,CLEANUP_POLICY = (STALE_QUERY_THRESHOLD_DAYS = 30),DATA_FLUSH_INTERVAL_SECONDS = 900,INTERVAL_LENGTH_MINUTES = 60,MAX_STORAGE_SIZE_MB = 100,QUERY_CAPTURE_MODE = ALL,SIZE_BASED_CLEANUP_MODE = AUTO);
USE Foo;
CREATE TABLE Test (a int,b nvarchar(max));
INSERT INTO Test SELECT 1,'string';

创建用于监视的扩展事件会话:

CREATE EVENT SESSION [Foo] ON SERVER 
ADD EVENT sqlserver.rpc_completed(SET collect_data_stream=(1)
    ACTION(sqlserver.client_app_name,sqlserver.client_hostname,sqlserver.client_pid,sqlserver.database_name,sqlserver.is_system,sqlserver.server_principal_name,sqlserver.session_id,sqlserver.session_server_principal_name,sqlserver.sql_text)
    WHERE ([writes]>(0))),ADD EVENT sqlserver.sql_batch_completed(SET collect_batch_text=(1)
    ACTION(sqlserver.client_app_name,sqlserver.sql_text)
    WHERE ([writes]>(0)))
ADD TARGET package0.event_file(SET filename=N'C:\temp\FooActivity2016.xel',max_file_size=(11),max_rollover_files=(999999))
WITH (MAX_MEMORY=32768 KB,EVENT_RETENTION_MODE=ALLOW_MULTIPLE_EVENT_LOSS,MAX_disPATCH_LATENCY=30 SECONDS,MAX_EVENT_SIZE=0 KB,MEMORY_PARTITION_MODE=NONE,TRACK_CAUSALITY=ON,STARTUP_STATE=OFF);

接下来运行以下内容

WHILE @@TRANCOUNT > 0 COMMIT
SET IMPLICIT_TRANSACTIONS ON;
SET NOCOUNT ON;
GO
DECLARE @b nvarchar(max);
SELECT @b = b FROM dbo.Test WHERE a = 1;
WAITFOR DELAY '00:00:01.000';
GO 86400

重现此事件可能需要或可能不需要隐式事务.

认情况下,在下一个小时的顶部,Query Store的统计信息收集作业将写出数据.这似乎(有时?)作为一小时内执行的第一个用户查询的一部分发生.扩展事件会话将显示类似于以下内容

事务日志显示已发生的写入:

USE Foo;
SELECT [Transaction ID],[Begin Time],SPID,Operation,[Description],[Page ID],[Slot ID],[Parent Transaction ID] 
FROM sys.fn_dblog(null,null) 
/* Adjust based on contents of your transaction log */
WHERE [Transaction ID] IN ('0000:0000042c','0000:0000042d','0000:0000042e')
OR [Parent Transaction ID] IN ('0000:0000042c','0000:0000042e')
ORDER BY [Current LSN];

使用DBCC PAGE检查页面显示写入是sys.plan_persist_runtime_stats_interval.

USE Foo;
DBCC TRACEON(3604); 
DBCC PAGE(5,1,344,1); SELECT
OBJECT_NAME(229575856);

请注意,日志条目显示三个嵌套事务,但只显示两个提交记录.在生产中的类似情况下,这导致了一个可以说是错误的客户端库,该库使用意外启动写入事务的隐式事务,从而阻止事务日志清除.编写库只是在运行更新,插入或删除语句后才发出提交,因此它从不发出提交命令并使写入事务处于打开状态.

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐