SELECT sorgusu neden yazma işlemine neden oluyor?


34

SQL Server 2016 SP1 CU6 çalıştıran bir sunucuda bazen bir Genişletilmiş Olaylar oturumunun, yazmaya neden olan bir SELECT sorgusu gösterdiğini fark ettim. Örneğin:

görüntü tanımını buraya girin

Yürütme planı, karma tablo, biriktirme veya TempDB'ye sıçrayabilecek sıralama gibi yazmaların açık bir nedenini göstermiyor:

görüntü tanımını buraya girin

Bir MAX tipine veya otomatik istatistik güncellemesine değişken ataması da buna neden olabilir, ancak bu durumda yazılanların nedeni de bu değildi.

Yazılar başka nelerden olabilir?

Yanıtlar:


8

sakar

Bunları orjinal cevabıma dahil edip etmediğimi hatırlayamadım , işte başka bir çift.

Makaralar!

SQL Server, geçici veri yapılarında tempdb'de depolanan birçok farklı makaraya sahiptir. İki örnek Tablo ve Dizin makaralarıdır.

Bir sorgu planında meydana geldiklerinde, bu makaralara yapılan yazma işlemi sorgu ile ilişkilendirilecektir.

FINDIK

Bunlar ayrıca DMV’lerde, profilerde, XE’de, vb.

Endeks Biriktirme

FINDIK

Masa biriktirme

FINDIK

Gerçekleştirilen yazma miktarı, biriktirilen verilerin boyutuna göre artacaktır.

Döküntüler

SQL Server belirli operatörler için yeterli bellek alamadığında, bazı sayfaları diske aktarabilir. Bu öncelikle çeşitler ve karmalar ile olur. Bunu gerçek uygulama planlarında görebilirsiniz ve SQL sunucusunun daha yeni sürümlerinde dökülmeler de dm_exec_query_stats içinde izlenir .

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;

FINDIK

FINDIK

Takip

Bunları kendi gösterilerinizde görmek için yukarıda kullandığım ile benzer bir XE oturumu kullanabilirsiniz.

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

Bazı durumlarda Sorgu Deposu, yazma işleminin select ifadesinin bir etkisi olarak ve aynı oturumda ortaya çıkmasına neden olabilir.

Bu, aşağıdaki gibi çoğaltılabilir:

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';

İzleme için bir Genişletilmiş Etkinlikler oturumu oluşturun:

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);

Sonra aşağıdakileri çalıştırın:

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

Bu işlemi çoğaltmak için örtük bir işlem gerekebilir veya olmayabilir.

Varsayılan olarak, sonraki saatin başında Query Store istatistik toplama işi veri yazacaktır. Bu (bazen?), Saat boyunca yürütülen ilk kullanıcı sorgusunun bir parçası olarak ortaya çıkar. Genişletilmiş Olaylar oturumu, aşağıdakine benzer bir şey gösterecektir:

görüntü tanımını buraya girin

İşlem günlüğü gerçekleşen yazmaları gösterir:

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];

görüntü tanımını buraya girin

Sayfayı incelemek DBCC PAGEyazarların yapılacağını gösterir sys.plan_persist_runtime_stats_interval.

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

Günlük girişlerinin iç içe geçmiş üç işlem gösterdiğini ancak yalnızca iki işlem kaydı gösterdiğini unutmayın. Üretimdeki benzer bir durumda, bu, beklenmedik bir şekilde yazma işlemine başlayan ve işlem günlüğünün temizlenmesini engelleyen gizli işlemleri kullanan tartışmasız hatalı bir müşteri kitaplığına yol açtı. Kütüphane, yalnızca bir güncelleme yaptıktan, bir ekleme yaptıktan veya silindikten sonra bir işlem yapmak için yazılmıştır, bu nedenle hiçbir zaman bir taahhüt komutu vermemiş ve bir yazma işlemi açık bırakmamıştır.


25

Bunun olabileceği başka bir zaman var, ve bu otomatik istatistik güncellemesi ile.

İşte bakacağımız XE oturumu:

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

Sonra bunu bilgi toplamak için kullanacağız:

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 Oturumu'nun ilginç sonuçlarından bazıları:

FINDIK

Otomatik istatistik güncellemesi herhangi bir yazı göstermiyor, ancak sorgu istatistik güncellemesinden hemen sonra bir yazma gösteriyor.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.