完全不同的查询的相同查询哈希

LCJ*_*LCJ 4 sql-server execution-plan

来自sys.dm_exec_query_stats 的Query_hash 定义 是:

query_hash:对查询计算的二进制哈希值,用于识别具有相似逻辑的查询。您可以使用查询哈希来确定仅在文字值上有所不同的查询的聚合资源使用情况。

但是当我搜索一个特定的 query_hash(如下所示)时,我得到了多个查询文本,这些文本在逻辑和size_in_bytes(计划)上有很大差异。

注意:我使用的是 SQL Server 2016

DECLARE @QueryHashTest BINARY(8)
SET @QueryHashTest = CONVERT(BINARY(8), 'Ð…U¹üŒv¿')

SELECT  
        QCP.objtype
        ,qStat.query_hash,
        CONVERT(VARCHAR(100),  qStat.query_Hash) AS VARCHAR_query_hash
        ,sText.text AS QueryText
        ,QCP.size_in_bytes
        ,qStat.creation_time
        ,qp.query_plan  
FROM ( 
        SELECT query_hash,
               COUNT(query_hash) AS PlanCount
        FROM sys.dm_exec_query_stats
        GROUP BY query_hash
    ) AS MultipleQ
INNER JOIN sys.dm_exec_query_stats qStat ON MultipleQ.query_hash = qStat.query_hash
INNER JOIN sys.dm_exec_cached_plans  QCP
    ON QCP.plan_handle = qStat.plan_handle
CROSS APPLY sys.dm_exec_sql_text(qStat.sql_handle) AS sText
CROSS APPLY sys.dm_exec_query_plan(qStat.plan_handle) AS qp
WHERE PlanCount > 1
AND QCP.objtype = 'Proc'
AND qStat.query_hash= @QueryHashTest 
AND (size_in_bytes >= 2179072 OR size_in_bytes <= 262144)
ORDER BY size_in_bytes DESC
Run Code Online (Sandbox Code Playgroud)

结果 在此处输入图片说明

为什么不相关的查询显示相同的 query_hash?这是一个错误还是数据库中发生了一些意想不到的事情?

For*_*est 6

虽然散列冲突是可能的,但我怀疑正在发生的事情是您正在提取整个批次的文本,而不是特定的语句。具有多个语句的过程可以为每个语句获取一个缓存条目。如果某些语句跨过程相同,它们将具有相同的查询哈希。让我演示一下:

USE TestDB
GO

--DROP TABLE dbo.employees
CREATE TABLE dbo.employees (
ID INT IDENTITY PRIMARY KEY,
title VARCHAR(20),
salary TINYINT,
has_been_fired_yet BIT)

INSERT dbo.employees
VALUES ('Senior DBA',30,0),('Grumpy DBA',50,0)
GO

CREATE OR ALTER PROC dbo.Payroll
AS

SELECT 'Your total payroll is '+CONVERT(VARCHAR(10),SUM(salary))+' query bucks'
FROM dbo.employees
WHERE has_been_fired_yet = 0
GO

CREATE OR ALTER PROC dbo.RightSizing
AS

UPDATE dbo.employees
SET has_been_fired_yet = 1
WHERE salary > 40

SELECT 'Your total payroll is '+CONVERT(VARCHAR(10),SUM(salary))+' query bucks'
FROM dbo.employees
WHERE has_been_fired_yet = 0
GO

--EXEC to get them in the cache
EXEC dbo.Payroll
EXEC dbo.RightSizing
Run Code Online (Sandbox Code Playgroud)

使用以下查询查看每个 proc 中的相同语句如何单独显示。

SELECT
st.text AS batch_text,
SUBSTRING(st.text, (qs.statement_start_offset/2) + 1,  
    ((CASE statement_end_offset   
        WHEN -1 THEN DATALENGTH(st.text)  
        ELSE qs.statement_end_offset 
    END - qs.statement_start_offset)/2) + 1
) AS statement_text,
qs.execution_count,
qs.query_hash
FROM sys.dm_exec_query_stats AS qs  
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) as st 
WHERE st.objectid IN (OBJECT_ID('dbo.Payroll'),OBJECT_ID('dbo.RightSizing'))
Run Code Online (Sandbox Code Playgroud)

查询结果 如果您在问题中使用该查询,则它无法选择相同的语句,因为它仅查看批处理文本。