Навіщо запит 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

У деяких випадках Магазин запитів може спричинити появу запису як ефект оператора 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

Невідповідна транзакція може бути або не потрібна для її відтворення.

За замовчуванням у верхній частині наступної години завдання збору статистики магазину запитів випише дані. Схоже, що (іноді?) Трапляється як частина першого запиту користувача, виконаного протягом години. Сеанс розширених подій покаже щось подібне до наступного:

введіть тут опис зображення

Журнал транзакцій показує записи, які відбулися:

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 PAGEпоказує, що записи потрібно робити sys.plan_persist_runtime_stats_interval.

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

Зауважте, що записи журналу показують три вкладені транзакції, але лише дві записи фіксації. У подібній ситуації у виробництві це призвело до того, що, мабуть, несправна бібліотека клієнтів, яка використовувала неявні транзакції, несподівано запускаючи транзакцію запису, не дозволяючи журналу транзакцій очищатись. Бібліотека була написана, щоб видати фіксацію лише після запуску операції оновлення, вставлення чи видалення, тому вона ніколи не видала команду фіксації та не залишала транзакції запису відкритою.


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:

Горіхи

Автоматичне оновлення статистики не відображає жодних записів, але запит показує один запис відразу після оновлення статистики.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.