克服LIKE字符长度限制


13

通过阅读这里的LIKE字符长度限制,看起来我在LIKE子句中发送的文本长度不能超过4000个字符。

我正在尝试从特定查询的查询计划缓存中获取查询计划。

SELECT *
FROM sys.dm_exec_cached_plans AS cp 
CROSS APPLY sys.dm_exec_query_plan(cp.plan_handle) AS qp 
CROSS APPLY sys.dm_exec_sql_text(cp.plan_handle) AS st
where st.text like '%MY_QUERY_LONGER_THAN_4000_CHARS%' ESCAPE '?'

如果其中的查询LIKE超过4000个字符,那么即使我的查询在缓存计划中,我也会得到0个结果。(我期待至少是错误)。

有没有办法解决此问题或采取其他措施?我的查询长度可能超过了>个10000字符,看起来好像无法使用来查找它们LIKE


2
也许可以where st.text like '%MY_QUERY%CHARS%' ESCAPE '?'
分文

4
您实际上是否有相同的查询文本(4,000个字符),然后又有所不同?
马丁·史密斯

@MartinSmith是的,我确实有这样的疑问。
Dan Dinu

Answers:


9

看来这不可能在纯T-SQL中解决,因为在“搜索”字符串中(即最多8000个或4000个字符),CHARINDEXPATINDEX不允许使用超过8000个字节。在以下测试中可以看到:VARCHARNVARCHAR

SELECT 1 WHERE CHARINDEX(N'Z' + REPLICATE(CONVERT(NVARCHAR(MAX), N'a'), 7000),
                         N'Z' + REPLICATE(CONVERT(NVARCHAR(MAX), N'a'), 6000)) > 0

SELECT 1 WHERE PATINDEX(N'Z' + REPLICATE(CONVERT(NVARCHAR(MAX), N'a'), 7000),
                        N'Z' + REPLICATE(CONVERT(NVARCHAR(MAX), N'a'), 6000)) > 0

这些查询都返回以下错误:

消息8152,级别16,状态10,行xxxxx
字符串或二进制数据将被截断。

并且,减少7000这些查询中的任何一个以3999消除错误。4000两种情况下的值也都会错误(由于N'Z'开头有多余的字符)。

但是,可以使用SQLCLR完成此操作。创建一个接受两个类型为的输入参数的标量函数非常简单NVARCHAR(MAX)

以下示例使用SQL# SQLCLR库的免费版本(我创建了该版本,但String_Contains在免费版本中再次可用:-)说明了此功能。

设定

-- DROP TABLE #ContainsData;
CREATE TABLE #ContainsData
(
  ContainsDataID INT NOT NULL IDENTITY(1, 1) PRIMARY KEY,
  Col1 NVARCHAR(MAX) NOT NULL
);

INSERT INTO #ContainsData ([Col1])
VALUES (N'Q' + REPLICATE(CONVERT(NVARCHAR(MAX), N'a'), 15000)),
       (N'W' + REPLICATE(CONVERT(NVARCHAR(MAX), N'a'), 20000)),
       (N'Z' + REPLICATE(CONVERT(NVARCHAR(MAX), N'a'), 70000));

-- verify the lengths being over 8000
SELECT tmp.[ContainsDataID], tmp.[Col1], DATALENGTH(tmp.[Col1])
FROM   #ContainsData tmp;

测试

SELECT tmp.[ContainsDataID], tmp.[Col1], DATALENGTH(tmp.[Col1])
FROM   #ContainsData tmp
WHERE  SQL#.String_Contains(tmp.[Col1], REPLICATE(CONVERT(NVARCHAR(MAX), N'a'), 15100)) = 1;
-- IDs returned: 2 and 3

SELECT tmp.[ContainsDataID], tmp.[Col1], DATALENGTH(tmp.[Col1])
FROM   #ContainsData tmp
WHERE  SQL#.String_Contains(tmp.[Col1], REPLICATE(CONVERT(NVARCHAR(MAX), N'a'), 26100)) = 1;
-- IDs returned: 3

请记住,String_Contains使用的是对所有内容敏感的(大小写,重音,假名和宽度)比较。


2

因为您还询问了其他方法,所以找到特定计划的另一种方法是plan_hash通过按以下方式更改查询来搜索它:

SELECT *
FROM sys.dm_exec_cached_plans AS cp 
INNER JOIN sys.dm_exec_query_stats qs
    ON cp.plan_handle = qs.plan_handle
CROSS APPLY sys.dm_exec_query_plan(cp.plan_handle) AS qp 
CROSS APPLY sys.dm_exec_sql_text(cp.plan_handle) AS st
WHERE qs.query_hash = 0xE4026347B5F49802

我找到要QueryHash搜索的值的最快方法是将有问题的查询粘贴到“查询”窗口中,然后显示“估计执行计划”。阅读XML输出,并QueryHashStmtSimple元素中查找属性,这将为您提供所需的内容。将QueryHash值插入上面的查询中,希望您已经找到了想要的东西。

这是一些屏幕截图,显示了QueryHash在我解释不佳的情况下如何快速获取价值。

显示估算的执行计划

在此处输入图片说明

显示执行计划XM ...

在此处输入图片说明

搜索QueryHash值

在此处输入图片说明

显然,如果您要查找的查询与您要为其显示“估计的执行计划”的查询不同,则该技巧将不起作用,但这可能比CLR例程附带的所有细微差别和使它们正常工作的速度更快。


0

如果您有权访问查询文本(意味着可以修改它们),则可以向感兴趣的人添加独特的注释:

select /* myUniqueQuery123 */ whatever from somewhere ...

然后myUniqueQuery123在计划缓存中而不是整个查询文本中进行搜索:

... where st.text like '%myUniqueQuery123%'

PS。未测试

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.