我应该相信 Query Store 运行时统计信息吗?

jer*_*ech 0 sql-server query-store

我在许多服务器上观察到的 Query Store 运行时统计数据存在这种奇怪的行为,这些行为具有不同的场景,这让我不敢相信这些统计数据。还是我做错了什么?

例如,具有给定查询计划的像这样的琐碎查询:

在此处输入图片说明

Stats ( sys.query_store_runtime_stats)max_logical_io_reads在某个偶然的时间间隔报告绝对疯狂的数字:

在此处输入图片说明

但是 table 总共只分配了 27 页!

我正在通过跨许多环境的不同查询遇到这种现象。它正在破坏我的回归查询分析。

具有不同读取次数的查询没有不同的计划。

堆表只显示很少更新和插入。巧合的是,我以堆为例。我在使用集群表时也遇到过这种情况。

Eri*_*ing 7

病理!

这可能会以不会影响计划的方式发生在查询中:

此外如果有统计信息更新、溢出、假脱机等,一些导致写入的选择可能会触发额外的读取。虽然这些都没有显示在您的计划中,但其他人可能会在稍后发现这个花絮有用。

DROP TABLE IF EXISTS dbo.el_heapo;
CREATE TABLE dbo.el_heapo ( col1 BIGINT, col2 VARCHAR(8000) DEFAULT 'A' );

INSERT dbo.el_heapo ( col1 )
SELECT TOP 1000000
       x.rn
FROM   (   SELECT     ROW_NUMBER() OVER ( ORDER BY ( SELECT 1 / 0 )) AS rn
           FROM       sys.messages AS m
           CROSS JOIN sys.messages AS m2 ) AS x;
Run Code Online (Sandbox Code Playgroud)

运行一个简单的查询:

SELECT COUNT_BIG(*)
FROM   dbo.el_heapo;

Table 'el_heapo'. Scan count 1, logical reads 2718 
CPU time = 62 ms,  elapsed time = 62 ms.
Run Code Online (Sandbox Code Playgroud)

查看表格:没有转发的提取。

SELECT OBJECT_NAME(ddips.object_id) AS TableName, 
       ddips.index_type_desc, 
       ddips.forwarded_record_count
FROM   sys.dm_db_index_physical_stats(DB_ID(), 
                                      OBJECT_ID('dbo.el_heapo'), 
                                      0, 
                                      NULL, 
                                      'DETAILED') AS ddips;
Run Code Online (Sandbox Code Playgroud)

导致一些转发的提取:

UPDATE dbo.el_heapo
SET    col2 = REPLICATE('Z', 1000)
WHERE  col1 % 3 = 0;
Run Code Online (Sandbox Code Playgroud)

如果您再次运行计数并转发 fetch 查询,您应该看到:

~330k forwarded fetches

Table 'el_heapo'. Scan count 1, logical reads 380564
 SQL Server Execution Times:
   CPU time = 359 ms,  elapsed time = 360 ms.
Run Code Online (Sandbox Code Playgroud)

但执行计划将是相同的。

索引

创建一个虚拟表,我不会弄乱我的真实用户表:

SELECT *
INTO dbo.TempUsers
FROM StackOverflow2013.dbo.Users AS u;

CREATE UNIQUE CLUSTERED INDEX c ON dbo.TempUsers(Id);
Run Code Online (Sandbox Code Playgroud)

检查桌子尺寸:

SELECT   TOP 2147483647 
         s.name AS schema_name,
         OBJECT_NAME(ps.object_id) AS table_name,         
         i.name AS index_name,
         ps.row_count,
         ps.in_row_used_page_count,
         (ps.reserved_page_count * 8. / 1024.) AS reserved_MB,
         (ps.lob_reserved_page_count * 8. / 1024.) AS reserved_LOB_MB,
         (ps.row_overflow_reserved_page_count * 8. / 1024.) AS reserved_row_overflow_MB
FROM     sys.dm_db_partition_stats AS ps
JOIN     sys.objects AS so
    ON  ps.object_id = so.object_id
    AND so.is_ms_shipped = 0
    AND so.type <> 'TF'
JOIN     sys.schemas AS s
    ON s.schema_id = so.schema_id
JOIN sys.indexes AS i
    ON ps.object_id = i.object_id
    AND ps.index_id = i.index_id
ORDER BY ps.object_id, ps.index_id, ps.partition_number
Run Code Online (Sandbox Code Playgroud)

应该是 44,450 页和 348MB。

简单查询:

SELECT COUNT(*)
FROM dbo.TempUsers AS tu

Table 'TempUsers'. Scan count 1, logical reads 44439
   CPU time = 219 ms,  elapsed time = 229 ms.
Run Code Online (Sandbox Code Playgroud)

将 DisplayName 列更新为最大长度 (nvarchar 40):

UPDATE t
SET t.DisplayName = t.DisplayName + REPLICATE('A', 40 - (DATALENGTH(t.DisplayName) / 2))
FROM dbo.TempUsers AS t
Run Code Online (Sandbox Code Playgroud)

现在表要大得多:

88,392 页,691MB。

查询结果:

Table 'TempUsers'. Scan count 1, logical reads 88381
   CPU time = 250 ms,  elapsed time = 245 ms.
Run Code Online (Sandbox Code Playgroud)