เหตุใดแบบสอบถามแบบ SELECT จะทำให้เกิดการเขียน


34

ฉันสังเกตว่าบนเซิร์ฟเวอร์ที่ใช้ SQL Server 2016 SP1 CU6 บางครั้งเซสชันเพิ่มเติมของกิจกรรมจะแสดงคิวรี SELECT ซึ่งทำให้เกิดการเขียน ตัวอย่างเช่น:

ป้อนคำอธิบายรูปภาพที่นี่

แผนการดำเนินการไม่แสดงสาเหตุที่ชัดเจนสำหรับการเขียนเช่นตารางแฮชสปูลหรือการเรียงลำดับที่สามารถรั่วไหลไปที่ TempDB:

ป้อนคำอธิบายรูปภาพที่นี่

การกำหนดตัวแปรให้กับประเภท MAX หรือการอัปเดตสถิติอัตโนมัติอาจทำให้เกิดสิ่งนี้ได้เช่นกัน แต่ก็ไม่ได้เป็นสาเหตุของการเขียนในกรณีนี้

การเขียนอาจมาจากอะไรอีก?

คำตอบ:


8

ซุ่มซ่าม

ฉันจำไม่ได้ว่าฉันรวมไว้ในคำตอบดั้งเดิมหรือไม่ดังนั้นนี่คือคู่อื่น

สิ่งของ!

SQL Server มีสปูลต่าง ๆ มากมายซึ่งเป็นโครงสร้างข้อมูลชั่วคราวที่เก็บไว้ใน tempdb ตัวอย่างที่สองคือเครื่องมือตารางและดัชนี

เมื่อเกิดขึ้นในแผนแบบสอบถามการเขียนไปยังสปูลเหล่านั้นจะเชื่อมโยงกับแบบสอบถาม

ถั่ว

สิ่งเหล่านี้จะถูกลงทะเบียนเป็นการเขียนใน DMV, profiler, XE เป็นต้น

ดัชนีสปูล

ถั่ว

ปูลโต๊ะ

ถั่ว

จำนวนของการเขียนที่ดำเนินการจะเพิ่มขึ้นตามขนาดของข้อมูลที่เก็บพักไว้อย่างชัดเจน

การรั่วไหล

เมื่อ SQL Server ไม่ได้รับหน่วยความจำเพียงพอสำหรับตัวดำเนินการบางอย่างมันอาจทำให้บางหน้าลงดิสก์ สิ่งนี้เกิดขึ้นกับการเรียงลำดับและแฮ็ชเป็นหลัก คุณสามารถดูนี้ในการวางแผนการดำเนินการที่เกิดขึ้นจริงและในรุ่นใหม่ของเซิร์ฟเวอร์ SQL, การรั่วไหลนอกจากนี้ยังมีการติดตามในdm_exec_query_stats

SELECT deqs.sql_handle,
       deqs.total_spills,
       deqs.last_spills,
       deqs.min_spills,
       deqs.max_spills
FROM sys.dm_exec_query_stats AS deqs
WHERE deqs.min_spills > 0;

ถั่ว

ถั่ว

การติดตาม

คุณสามารถใช้เซสชั่น XE ที่คล้ายกันกับที่ฉันใช้ด้านบนเพื่อดูสิ่งเหล่านี้ในการสาธิตของคุณเอง

CREATE EVENT SESSION spools_and_spills
    ON SERVER
    ADD EVENT sqlserver.sql_batch_completed
    ( ACTION ( sqlserver.sql_text ))
    ADD TARGET package0.event_file
    ( SET filename = N'c:\temp\spools_and_spills' )
    WITH ( MAX_MEMORY = 4096KB,
           EVENT_RETENTION_MODE = ALLOW_SINGLE_EVENT_LOSS,
           MAX_DISPATCH_LATENCY = 1 SECONDS,
           MAX_EVENT_SIZE = 0KB,
           MEMORY_PARTITION_MODE = NONE,
           TRACK_CAUSALITY = OFF,
           STARTUP_STATE = OFF );
GO

38

ในบางกรณี 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.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 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:0000042d', '0000:0000042e')
ORDER BY [Current LSN];

ป้อนคำอธิบายรูปภาพที่นี่

ตรวจสอบหน้าเว็บที่มีแสดงให้เห็นว่าการเขียนเพื่อDBCC PAGEsys.plan_persist_runtime_stats_interval

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

โปรดทราบว่ารายการบันทึกแสดงธุรกรรมที่ซ้อนกันสามรายการ แต่มีระเบียนการส่งมอบเพียงสองรายการ ในสถานการณ์ที่คล้ายกันในการผลิตสิ่งนี้นำไปสู่ไลบรารีไคลเอ็นต์ที่มีข้อผิดพลาดที่ใช้ธุรกรรมโดยนัยโดยไม่คาดคิดในการเริ่มต้นธุรกรรมการเขียนป้องกันการทำธุรกรรมบันทึกจากการล้าง ไลบรารีถูกเขียนเพื่อออกคำสั่ง commit หลังจากรันอัพเดต, แทรกหรือลบคำสั่งเท่านั้นดังนั้นจึงไม่เคยออกคำสั่ง commit และเปิดธุรกรรมการเขียนค้างไว้


25

มีอีกครั้งที่สิ่งนี้อาจเกิดขึ้นและนั่นคือการอัพเดตสถิติอัตโนมัติ

นี่คือเซสชั่น XE ที่เราจะดู:

CREATE EVENT SESSION batches_and_stats
    ON SERVER
    ADD EVENT sqlserver.auto_stats
    ( ACTION ( sqlserver.sql_text )),
    ADD EVENT sqlserver.sql_batch_completed
    ( ACTION ( sqlserver.sql_text ))
    ADD TARGET package0.event_file
    ( SET filename = N'c:\temp\batches_and_stats' )
    WITH ( MAX_MEMORY = 4096KB,
           EVENT_RETENTION_MODE = ALLOW_SINGLE_EVENT_LOSS,
           MAX_DISPATCH_LATENCY = 30 SECONDS,
           MAX_EVENT_SIZE = 0KB,
           MEMORY_PARTITION_MODE = NONE,
           TRACK_CAUSALITY = OFF,
           STARTUP_STATE = OFF );
GO

จากนั้นเราจะใช้สิ่งนี้เพื่อรวบรวมข้อมูล:

USE tempdb

DROP TABLE IF EXISTS dbo.SkewedUp

CREATE TABLE dbo.SkewedUp (Id INT NOT NULL, INDEX cx_su CLUSTERED (Id))

INSERT dbo.SkewedUp WITH ( TABLOCK ) ( Id )
SELECT CASE WHEN x.r % 15 = 0 THEN 1
            WHEN x.r % 5 = 0 THEN 1000
            WHEN x.r % 3 = 0 THEN 10000
            ELSE 100000
       END AS Id
FROM   (   SELECT     TOP 1000000 ROW_NUMBER() OVER ( ORDER BY @@DBTS ) AS r
           FROM       sys.messages AS m
           CROSS JOIN sys.messages AS m2 ) AS x;


ALTER EVENT SESSION [batches_and_stats] ON SERVER STATE = START

SELECT su.Id, COUNT(*) AS records
FROM dbo.SkewedUp AS su
WHERE su.Id > 0
GROUP BY su.Id

ALTER EVENT SESSION [batches_and_stats] ON SERVER STATE = STOP

ผลลัพธ์ที่น่าสนใจบางส่วนจากเซสชัน XE:

ถั่ว

การอัปเดตสถิติอัตโนมัติไม่แสดงการเขียนใด ๆ แต่เคียวรีจะแสดงการเขียนหนึ่งรายการทันทีหลังจากการอัพเดตสถิติ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.