LIKE karakter uzunluğu sınırlamasını aş


13

Bu LIKE karakter uzunluğu sınırlamasını burada okuyarak , LIKE yan tümcesinde ~ 4000 karakterden daha uzun bir metin gönderemiyorum.

Belirli bir sorgu için sorgu planı önbelleğinden sorgu planı almaya çalışıyorum.

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

içindeki sorgu LIKE4000 karakterden uzunsa, sorgum önbellek planında olsa bile 0 sonuç alıyorum. (En azından bir erorr bekliyordum).

Bu sorunu geçici olarak çözmenin veya farklı bir şekilde yapmanın bir yolu var mı? 10000Uzun chars > olabilir sorguları var ve ben onları ile bulamıyorum gibi görünüyor LIKE.


2
Belki de metni where st.text like '%MY_QUERY%CHARS%' ESCAPE '?'
parçalayın

4
4.000 karakterle özdeş olan ve sonra farklı olan sorgu metinleriniz var mı?
Martin Smith

@MartinSmith evet, böyle sorgularım var.
Dan Dinu

Yanıtlar:


9

Yana saf T-SQL çözülebileceğini görünen ne değildir CHARINDEX, ne de PATINDEXdize "aramak için" (8000 yani max fazla 8000 bayt kullanarak izin VARCHARveya 4000 NVARCHARkarakterden). Bu aşağıdaki testlerde görülebilir:

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

Bu sorguların her ikisi de aşağıdaki hatayı döndürür:

Msg 8152, Seviye 16, Durum 10, Satır xxxxx
Dize veya ikili veriler kesilir.

Ve 7000bu sorgulardan herhangi birinde azaltmak 3999hatadan kurtulmak için. Her 4000iki durumda da bir değer hata verir ( N'Z'başlangıçtaki ekstra karakterden dolayı ).

Ancak, bu SQLCLR kullanılarak gerçekleştirilebilir. İki tür giriş parametresini kabul eden bir skaler fonksiyon oluşturmak oldukça basittir NVARCHAR(MAX).

Aşağıdaki örnek, SQL # SQLCLR kütüphanesinin Ücretsiz sürümünü (oluşturduğum ancak String_Contains'ı yine Ücretsiz sürümü :-) kullanılabilir kullanarak bu yeteneği göstermektedir .

KURMAK

-- 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;

TESTLERİ

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

Lütfen String_Contains'ın her şeye duyarlı (büyük / küçük harf, aksan, Kana ve genişlik) karşılaştırmayı kullandığını unutmayın.


2

Alternatif yaklaşımlar da istemiş olduğunuz için, belirli bir plan bulmanın başka bir yolu da plan_hashsorgunuzu aşağıdaki gibi değiştirerek planını aramaktır:

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

QueryHashAranacak değeri elde etmenin en hızlı yolu , söz konusu sorguyu bir Sorgu Penceresine yapıştırmak ve ardından Tahmini Yürütme Planını görüntülemek. XML çıktısını okuyun ve öğedeki QueryHashniteliği arayın StmtSimpleve bu size ihtiyacınız olanı verecektir. QueryHash değerini yukarıdaki sorguya takın ve umarım aradığınızı bulmalısınız.

Burada QueryHash, kötü bir şekilde açıklamam durumunda değeri nasıl hızlı bir şekilde alacağımı gösteren bazı ekran görüntüleri .

Tahmini Yürütme Planını Görüntüle

resim açıklamasını buraya girin

Yürütme Planını Göster XM ...

resim açıklamasını buraya girin

QueryHash Değeri Ara

resim açıklamasını buraya girin

Açıkçası, aradığınız sorgu, Tahmini Yürütme Planını görüntülediğiniz sorgudan farklıysa, işe yaramaz, ancak bu, CLR rutinleri ile gelen ve bunların düzgün çalışmasını sağlayan tüm nüanslardan daha hızlı olabilir.


0

Sorgu metinlerine erişiminiz varsa (yani bunları değiştirebilirsiniz), ilgilendiğiniz kişilere benzersiz yorumlar ekleyebilirsiniz:

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

daha sonra myUniqueQuery123sorgu metninin tamamı yerine plan önbelleğinde arama yapın :

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

PS. Test edilmedi

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.