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 '?'

यदि के अंदर क्वेरी LIKE4000 वर्णों से अधिक है, तो मुझे 0 परिणाम प्राप्त होते हैं, भले ही मेरी क्वेरी कैश योजना में हो। (मैं कम से कम एक खून बह रहा था) की उम्मीद कर रहा था।

क्या इस मुद्दे को हल करने या इसे अलग तरीके से करने का कोई तरीका है? मेरे पास ऐसे प्रश्न हैं जो 10000लंबे समय तक हो सकते हैं और ऐसा लगता है कि मैं उनके साथ नहीं मिल सकता LIKE


2
शायद पाठ को तोड़ दें ... क्योंकि आपके पास एक-दूसरे के समान कई प्रश्न नहीं होने चाहिए:where st.text like '%MY_QUERY%CHARS%' ESCAPE '?'
scsimon

4
क्या आपके पास वास्तव में क्वेरी पाठ हैं जो 4,000 वर्णों के लिए समान हैं और फिर भिन्न हैं?
मार्टिन स्मिथ

@MartinSmith हाँ, मेरे पास इस तरह के प्रश्न हैं।
दान दीनू

जवाबों:


9

ऐसा नहीं लगता है कि इसे शुद्ध टी-एसक्यूएल में हल किया जा सकता है CHARINDEXऔर न तो PATINDEX"स्ट्रिंग" (अर्थात अधिकतम 8000 VARCHARया 4000 NVARCHARवर्ण) की खोज करने के लिए 8000 से अधिक बाइट्स का उपयोग करने की अनुमति है । इसे निम्नलिखित परीक्षणों में देखा जा सकता है:

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

उन दोनों प्रश्नों में निम्नलिखित त्रुटि है:

Msg 8152, Level 16, State 10, Line xxxxx
स्ट्रिंग या बाइनरी डेटा को छोटा कर दिया जाएगा।

और, त्रुटि से छुटकारा पाने के लिए 7000नीचे दिए गए प्रश्नों में से किसी एक को कम करना 39994000दोनों मामलों में एक मूल्य भी त्रुटि देगा ( 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खोज करने के लिए मान प्राप्त किया है, वह क्वेरी को क्वेरी विंडो में पेस्ट करने के लिए है और फिर अनुमानित निष्पादन योजना प्रदर्शित करें। एक्सएमएल आउटपुट पढ़ें और तत्व QueryHashमें विशेषता देखें StmtSimpleऔर यह आपको वह देनी चाहिए जो आपको चाहिए। ऊपर क्वेरी में QueryHash मान प्लग करें और उम्मीद है कि आपके पास वह होना चाहिए जो आप खोज रहे हैं।

यहां कुछ स्क्रीनशॉट दिखाए जा रहे हैं कि जिस QueryHashस्थिति में मैं इसे खराब तरीके से समझा रहा हूं, उसका मूल्य कैसे प्राप्त किया जा सकता है।

अनुमानित निष्पादन योजना प्रदर्शित करें

यहाँ छवि विवरण दर्ज करें

निष्पादन योजना एक्सएम दिखाएँ ...

यहाँ छवि विवरण दर्ज करें

QueryHash मान के लिए खोजें

यहाँ छवि विवरण दर्ज करें

यदि आप जिस क्वेरी के लिए अनुमानित एक्ज़ेक्यूशन प्लान प्रदर्शित कर रहे हैं, उस क्वेरी से अलग दिख रहे प्रश्न के लिए स्पष्ट रूप से चाल काम नहीं करेगी, लेकिन यह उन सभी बारीकियों की तुलना में तेज़ हो सकती है जो सीएलआर रूटीन के साथ आती हैं और जिन्हें ठीक से काम करना है।


0

यदि आपके पास क्वेरी पाठ तक पहुंच है (मतलब आप उन्हें संशोधित कर सकते हैं), तो आप उन लोगों के लिए अद्वितीय टिप्पणियां जोड़ सकते हैं जिनमें आपकी रुचि है:

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

फिर myUniqueQuery123पूरे क्वेरी टेक्स्ट के बजाय प्लान कैश में खोजें:

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

पुनश्च। टेस्ट नहीं हुआ

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.