SQL Server 2014'te CLR'yi Kilitleme (Windows 2012R2)


12

Sütunlarda bir dize üzerinde RegEX işlevi yapan bu küçük CLR var.

Windows Server 2012R2'de SQL Server 2014 (12.0.2000) üzerinde çalışırken, işlem

Msg 0, Seviye 11, Durum 0, Satır 0 Geçerli komutta ciddi bir hata oluştu. Varsa sonuçlar atılmalıdır.

ve eğer yaparsam bir yığın dökümü verir

select count (*) from table where (CLRREGEX,'Regex')

ama yaptığımda

select * from table where (CLRREGEX,'Regex') 

satırları döndürür.

Windows 8.1 üzerinde çalışan aynı SQL Server derlemesinde mükemmel çalışır.

Herhangi bir fikir?

- Düzenle Olabildiğince basit

using System;
using System.Collections.Generic;
using System.Text;
using System.Data.SqlTypes;           //SqlString, SqlInt32, SqlBoolean
using System.Text.RegularExpressions; //Match, Regex
using Microsoft.SqlServer.Server;     //SqlFunctionAttribute
public partial class UserDefinedFunctions
{
    public static readonly RegexOptions Options = RegexOptions.IgnorePatternWhitespace | RegexOptions.Multiline;
    [SqlFunction]
    [Microsoft.SqlServer.Server.SqlFunction(IsDeterministic = true, IsPrecise = true)]
    public static SqlBoolean RegExMatch(SqlString input, SqlString pattern)
    {
        if (input.IsNull || pattern.IsNull) //nulls dont qualify for a match
            return SqlBoolean.False;
    return Regex.IsMatch(input.Value, pattern.Value, RegexOptions.IgnoreCase);
    }
}

Yani küçük değişiklikler ile bu şimdi çalışıyor: C # ana ders örtülü veri dönüştürme sakının TSQL ile aynı gibi görünüyor.

using System;
using System.Text;
using System.Data.SqlTypes;           //SqlString, SqlInt32, SqlBoolean
using System.Text.RegularExpressions; //Match, Regex
using Microsoft.SqlServer.Server;     //SqlFunctionAttribute
public partial class UserDefinedFunctions
{
public static readonly RegexOptions Options = RegexOptions.IgnorePatternWhitespace | RegexOptions.Singleline | RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.CultureInvariant;

    [Microsoft.SqlServer.Server.SqlFunction(IsDeterministic = true, IsPrecise = true, DataAccess = DataAccessKind.Read)]
    public static SqlBoolean RegExMatch(SqlString input, SqlString pattern)
{
    if (input.IsNull || pattern.IsNull) //nulls dont qualify for a match
        return SqlBoolean.False;
    string sqldata = input.ToString();
    string regex = pattern.ToString();
    return Regex.IsMatch(sqldata, regex);
 }

Bu tüm kalıplar için mi yoksa sadece bu kalıp için mi? Verimsiz bir desen olabilir (yani aşırı geri izleme veya gereksiz Yakalamalar). MatchTimeout özelliğini ayarlamanız gerekir (.NET Framework 4.5'te yeni). RegEx işlevini kendiniz kodladınız mı? Öyleyse, statik veya örnek RegEx yöntemleri kullanıyor musunuz? Is SqlFunctionyöntem olarak işaretlenmiş IsDeterministic=true? Montaj işaretli SAFEmi?
Solomon Rutzky

2
Bu masalar ne kadar büyük? Ayrıca, sorun ifadeleri için tahmini planın paralel bir işleci olup olmadığını kontrol edebilir misiniz? Evet ise, sorunun paralellik olmadan ortaya çıkıp çıkmadığını kontrol edebilir misiniz, yani MAXDOP = 1 ipucu.
Amit Banerjee

2
Yinelenen [SqlFunction]öznitelik dışında kod iyi görünüyor . Bu tam kod mu? Bunun derleneceğini sanmıyorum. 4.0 / 4.5 / 4.5.x / etc sürümünü ya da CLR sürüm 4'e bağlı SQL Server 2014'te bulunduğunuzdan bu sunucuda ne varsa Framework sürüm 2.0 / 3.0 / 3.5 ayrımı bir sorun oluşturmaz. sorun 32-bit gösteren sunucu? Diğer sunuculara kıyasla ne kadar bellek var? Ve bu hatayı aldıktan hemen sonra SQL Server günlüklerini kontrol ettiniz mi?
Solomon Rutzky

2
.NET'in tam sürümü sorunla ilgili değildir, ancak bu, yeni MatchTimeoutözelliği kullanabileceğiniz anlamına geleceği için tüm sunucuların en az 4.5'te olup olmadığını bilmek güzel olurdu . Ama sadece 5 karakter geçiyorsan ya gerçekten sorun olduğunu sanmıyorum. O ise bu bir makine .NET Framework yüklemek bozuk olması mümkün ve alabalık balıkçılık faaliyetleri ;-) durdurdu kez bu tamir edilebilir. Ayrıca, [0-9].*ilk basamaktan sonra varsa tüm karakterlerle eşleştiği için basit ama aynı zamanda verimsizdir; sadece bir [0-9]için kullanmak IsMatchdaha iyidir.
Solomon Rutzky

1
Neden değiştirdiniz DataAccessKindiçin Read? Bu sadece yavaşlatır ve herhangi bir veri erişimi yapmazsınız. Ayrıca, şu anda çalışıyor gibi görüyorum, ama ToString kodlamaları düzgün bir şekilde işlediğini veya böyle bir şey düşünmüyorum gibi özellik ToString()yerine aksine yöntemi kullanarak dikkatli Valueolurum. Veritabanları harmanlama ayarınız nedir? Tabii ki, yukarıdaki yorumlarınızdan birini tekrar okudum ve sütunun NVARCHAR yerine VARCHAR olduğunu görüyorum. Bu alanın veritabanından farklı bir harmanlaması var mı?
Solomon Rutzky

Yanıtlar:


4

Sorun, Windows işletim sistemi ve SQL Server (özellikle derlemenin yüklü olduğu veritabanı) arasındaki yerel bir çakışmadır. Her ikisinin de neye ayarlandığını görmek için aşağıdaki sorguyu çalıştırabilirsiniz:

SELECT os_language_version,
       DATABASEPROPERTYEX(N'{name of DB where Assembly exists}', 'LCID') AS 'DatabaseLCID'
FROM   sys.dm_os_windows_info;

Eğer farklılarsa, gördüğünüz gibi kesinlikle "tuhaf" davranışlar elde edebilirsiniz. Sorun şudur:

  • SqlStringmetnin kendisinden daha fazlasını içerir: derlemenin bulunduğu veritabanının varsayılan harmanlamasını içerir. Harmanlama iki bilgi parçasından oluşur: yerel bilgi (yani LCID) ve büyük / küçük harf, aksan, kana, genişlik veya her şeye (ikili ve ikili2) duyarlılığı ayrıntılandıran karşılaştırma seçenekleri (örn. SqlCompareOptions).
  • NET'te dize işlemleri, açıkça bir yerel ayar verilmedikçe, Windows'ta ayarlanan geçerli iş parçacığının yerel ayar bilgilerini (yani İşletim Sistemi / OS) kullanın.

Çakışma genellikle bir SqlString parametresini kullanmadan .Valueveya .ToString()örtük bir dönüşüm gerçekleştirecek şekilde başvururken ortaya çıkar SqlString. Bu durumda, LCID'lerin eşleşmediğini söyleyen bir istisnaya neden olur.

Görünüşe göre bu durumda gösterildiği gibi Regex kullanmak da dahil olmak üzere (bazı / tüm?) Dize karşılaştırmaları yapmak gibi diğer senaryolar vardır (şimdiye kadar bunu çoğaltmayı başaramadım).

Düzeltmeler için bazı fikirler:

İdeal (karşılaştırmanın nasıl işlediğine dair beklentiler her zaman karşılanacaktır):

  • Windows veya SQL Server LCID'yi (varsayılan dil), her ikisinin de eşleşeceği şekilde değiştirin

İdeal olandan daha az (Windows yerel ayarının davranışı eşitlik ve sıralama için aynı kurallar olmayabilir ve bu nedenle beklenmedik sonuçlar olabilir ):

  • İşlemlerin tümü OS LCID'yi kullanacak şekilde SQL Server LCID olmadan dizeyi döndüren .ToStringyöntemi veya .Valueözelliği kullanın .

Yardımcı olabilir:

  • Belki kullanmak SqlCharsyerine SqlStringSQL Server LCID ve harmanlama info boyunca getirmiyor olarak
  • Kültürün aşağıdakiler yoluyla önemli olmadığını belirtin StringComparison.InvariantCulture:
    • String.Compare(string, string, StringComparison.InvariantCulture) veya String.Compare(string, string, StringComparison.InvariantCultureIgnoreCase)
    • Normal İfade için şunu belirtin RegexOptions.CultureInvariant

1

Güncellenmiş..

Srutzky'nin işaret ettiği gibi SQL Engine ve pencere Sunucusu arasındaki yerelleştirme farklıdır:

os_language_version SqlServerLCID
1033 1039

Aşağıdaki kod değişikliği - seçeneğin ayarlanması RegexOptions.CultureInvarianthatayı alır. Değişmeyen kod, Windows Server 2012R2'de SQL Server 2012'yi aynı dil ayarlarıyla kilitlemez, ancak SQL Server 2014'te kilitler.

using System;
using System.Text;
using System.Data.SqlTypes;           //SqlString, SqlInt32, SqlBoolean
using System.Text.RegularExpressions; //Match, Regex
using Microsoft.SqlServer.Server;     //SqlFunctionAttribute
public partial class UserDefinedFunctions
{
public static readonly RegexOptions Options = RegexOptions.IgnorePatternWhitespace | RegexOptions.Singleline | RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.CultureInvariant;

    [Microsoft.SqlServer.Server.SqlFunction(IsDeterministic = true, IsPrecise = true)]
    public static SqlBoolean RegExMatch(SqlString input, SqlString pattern)
{
    if (input.IsNull || pattern.IsNull) //nulls dont qualify for a match
        return SqlBoolean.False;
    string sqldata = input.ToString();
    string regex = pattern.ToString();
    return Regex.IsMatch(sqldata, regex);
 }

Eğer çökmesini sunucuda aşağıdaki çalıştırmak misiniz: SELECT os_language_version, SERVERPROPERTY('LCID') AS 'SqlServerLCID' FROM sys.dm_os_windows_info;. Sorunun dil ayarlarında bir çelişki olması oldukça olasıdır. Çözümünüz hala en iyi yol olabilir, ancak genellikle s üzerindeki özellik ToString()yerine kullanıma gerek yoktur . Bu yüzden durumu teyit etmek güzel olurdu. ValueSqlString
Solomon Rutzky

Ben netleştirmek için yanıt gönderdi, ancak sorun olmamalı ayarlanmasıyla çözülebilir RegexOptions.CultureInvariantEğer geçemiyor çünkü Optionsiçine değişken Regex.IsMatch(sqldata, regex). Orijinal kodunuz ile yeni, çalışan kod arasında değişen şey, kullanmaya SqlString.Valuebaşlamanızdır SqlString.ToString(). Kullanmaya geçtiyseniz aynı sabit davranışı göreceğinizden şüpheleniyorum SqlChars. Ama bunu bir test olarak yapardım. En iyi yaklaşım, Windows veya SQL Server'ın LCID'sini diğerine uyacak şekilde değiştirmektir. Options statik değişkenini de kaldırabilirsiniz.
Solomon Rutzky

Merhaba. Cevabımı kabul ettiğin için teşekkürler :). Tıpkı daha fazla araştırma yaptım, söz ve ben OS ve SQL Server arasında farklı bir LCID olma nedeni kökü hakkında doğru olduğum sürece Sonra, ne görüyordum anlaşıldığı takdirde, değil mi ya, ilişkili olmamalıdır .Valuemülkiyet a SqlStringifadesinin, yöntemle aynı dahili değeri döndürdüğü anlaşılır .ToString(). Hala araştırıyorum ve cevabımı bulduğum her şeyle güncelleyeceğim :).
Solomon Rutzky

Cevabımı yeni bilgiler ışığında ayarladım. Bu senaryoyu yeniden oluşturamıyorum. Sorudaki kod gerçekten ne kullandığınız / kullandığınız mı? Aralarındaki tek gerçek fark, hataların biri diğerinin kullanmadığıdır RegexOptions.IgnoreCase. Ben benzer bir ortam kurduk: Windows (8.0) LCID 1033 kullanarak, SQL Server DB 1039 LCID vardır, aynı RegEx kullanarak , bir tablo üzerinde GUID'lerle dolu COUNT(*)bir VARCHARalanda bir desen kullanarak , yapıyor '[0-3â].*'10 milyon sıra ile. 2014 değil, SQL Server 2012'dir, ancak bunun önemli olması gerektiğini düşünmüyorum.
Solomon Rutzky

1
Tüm cevaplar için teşekkürler. Sorudaki kod ne kullanıyordum. Gerçekten karmaşık bir normal ifadem vardı ama bunu çok basit bir şekilde kullanarak çökmeyi başardım.
RegexOptions.CultureInvariant
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.