查询 sys.dm_exec_query_plan 时出现消息 6355“无法将一个或多个字符从 XML 转换为目标排序规则”

Mar*_*lli 5 xml sql-server collation execution-plan encoding

我喜欢在旅途中查找丢失的索引,查看执行计划

如果我想改进当前正在运行的东西,它可能会给我一个进一步的指示。

为此,我使用以下查询:

SET NOCOUNT ON
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED


SELECT 
    er.session_id,
    er.blocking_session_id,
    er.start_time,
    er.status,
    dbName = DB_NAME(er.database_id),
    er.wait_type,
    er.wait_time,
    er.last_wait_type,
    er.granted_query_memory,
    er.reads,
    er.logical_reads,
    er.writes,
    er.row_count,
    er.total_elapsed_time,
    er.cpu_time,
    er.open_transaction_count,
    er.open_transaction_count,
    s.text,
    qp.query_plan,
    logDate = CONVERT(DATETIME,GETDATE()),
    logTime = CONVERT(DATETIME,GETDATE())
FROM sys.dm_exec_requests er 
CROSS APPLY sys.dm_exec_sql_text(er.sql_handle) s
CROSS APPLY sys.dm_exec_query_plan(er.plan_handle) qp
WHERE 
    CONVERT(VARCHAR(MAX), qp.query_plan) LIKE '%<missing%'
Run Code Online (Sandbox Code Playgroud)

它通常工作正常;但是,我最近遇到了整理和 XML 的问题:

在此处输入图片说明

错误信息说:

SET NOCOUNT ON
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED


SELECT 
    er.session_id,
    er.blocking_session_id,
    er.start_time,
    er.status,
    dbName = DB_NAME(er.database_id),
    er.wait_type,
    er.wait_time,
    er.last_wait_type,
    er.granted_query_memory,
    er.reads,
    er.logical_reads,
    er.writes,
    er.row_count,
    er.total_elapsed_time,
    er.cpu_time,
    er.open_transaction_count,
    er.open_transaction_count,
    s.text,
    qp.query_plan,
    logDate = CONVERT(DATETIME,GETDATE()),
    logTime = CONVERT(DATETIME,GETDATE())
FROM sys.dm_exec_requests er 
CROSS APPLY sys.dm_exec_sql_text(er.sql_handle) s
CROSS APPLY sys.dm_exec_query_plan(er.plan_handle) qp
WHERE 
    CONVERT(VARCHAR(MAX), qp.query_plan) LIKE '%<missing%'
Run Code Online (Sandbox Code Playgroud)

我已经找到了导致它的原因:

 -- get only the applications from Italy:
exec usp_sel_outstandingItems            
                                    @startdate='2021-04-07 00:00:00',           
                                    @endDate='2021-08-15 00:00:00',           
                                    @statusDateStart=NULL,           
                                    @statusDateEnd=NULL,           
                                    @office=N'UK',           
                                    @country=N'IT ',           
                                    @userState=N'ParticipantPlaced',           
                                    @outstandingBalance=0
Run Code Online (Sandbox Code Playgroud)

我的问题是:

我的查询中的哪些内容对排序规则感到不安?
我该怎么做才能克服这个错误?

整理提示?

Msg 6355, Level 16, State 1, Line 40
Conversion of one or more characters from XML to target collation impossible
Run Code Online (Sandbox Code Playgroud)

Sol*_*zky 9

问题在于您正在将XML存储为 Unicode(特别是 UTF-16)的数据转换为 8 位数据。8 位数据需要代码页才能知道要使用哪一组最多 256 个字符(如果使用双字节字符集,则最多大约 24k 个字符,但绝大多数情况下最多 256 个字符)。这里的问题是 XML 数据中存在一个字符(或可能是多个字符):a) 在当前数据库的默认排序规则指定的代码页中不存在,或者 b) 在任何代码页中都不存在。

例如,以下查询显示大多数代码页中不存在的字符(或可能不存在),因此在转换为 时会出现相同的错误VARCHAR,但转换为NVARCHAR有效:

SELECT NCHAR(0x1234);
-- ?

DECLARE @Test XML;
SET @Test = CONVERT(XML, N'<a>' + NCHAR(0x1234) + N'</a>')
SELECT @Test;
-- <a>?</a>

SELECT CONVERT(NVARCHAR(MAX), @Test);
-- <a>?</a>

SELECT CONVERT(VARCHAR(MAX), @Test);
/*
Msg 6355, Level 16, State 1, Line XXXXX
Conversion of one or more characters from XML to target collation impossible
*/
Run Code Online (Sandbox Code Playgroud)

请转换为NVARCHAR(MAX)而不是VARCHAR(MAX)。你的WHERE谓词应该是:

CONVERT(NVARCHAR(MAX), qp.query_plan) LIKE N'%<missing%'
Run Code Online (Sandbox Code Playgroud)

(请注意在字符串字面量前添加了“N”——这不是必需的,但要养成一个好习惯)。

转换XML数据VARCHAR是唯一真正安全的,如果该查询是在具有UTF-8的排序规则作为默认排序规则数据库中执行,而这仅仅是在SQL Server 2019提供起动。

最后,回答您的“是否会通过COLLATE帮助强制进行整理?”的问题:不,不是从XML. 您不能将该COLLATE子句添加到XML数据中,因为排序规则不适用于XML(您会得到“表达式类型 xml 对 COLLATE 子句无效。”)。并且,将COLLATE外部放置在转换CONVERT()无济于事,因为这在此处失败了。您也不能将 紧跟在 the之后,因为它是数据类型而不是数据(您会得到“关键字 'COLLATE' 附近的语法不正确。”)。COLLATEVARCHAR(MAX)


有关使用排序规则/编码/Unicode 的更多信息,请访问我的网站:排序规则信息


归档时间:

查看次数:

275 次

最近记录:

4 年,4 月 前