Sự cố CLR trên SQL Server 2014 (windows 2012R2)


12

Tôi có CLR nhỏ này thực hiện chức năng RegEX trên một chuỗi trong các cột.

Khi chạy trên SQL Server 2014 (12.0.2000) trên Windows Server 2012R2, quá trình gặp sự cố với

Msg 0, Cấp 11, Trạng thái 0, Dòng 0 Đã xảy ra lỗi nghiêm trọng trên lệnh hiện tại. Các kết quả, nếu có, cần được loại bỏ.

và đưa ra một bãi chứa ngăn xếp nếu tôi làm

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

nhưng khi tôi làm

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

nó trả về các hàng

Hoạt động hoàn hảo trên cùng một bản dựng SQL Server chạy trên Windows 8.1.

Có ý kiến ​​gì không?

- Chỉnh sửa Nó đơn giản như nó có thể được

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

Vì vậy, bằng những thay đổi nhỏ, công việc này hiện đang hoạt động: Bài học chính về C # dường như giống như trong TSQL hãy cẩn thận với việc chuyển đổi dữ liệu ngầm.

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

Điều này xảy ra cho tất cả các mẫu hoặc chỉ cái này? Nó có thể là một mô hình không hiệu quả (nghĩa là quay lui quá mức hoặc Chụp không cần thiết). Bạn nên xem xét việc thiết lập thuộc tính MatchTimeout (mới trong .NET Framework 4.5). Bạn đã tự viết mã cho hàm RegEx chưa? Nếu vậy, bạn đang sử dụng các phương thức RegEx tĩnh hoặc thể hiện? Là SqlFunctionphương pháp được đánh dấu là IsDeterministic=true? Là lắp ráp được đánh dấu là SAFE?
Solomon Rutzky

2
Những cái bàn này lớn cỡ nào? Ngoài ra, bạn có thể kiểm tra xem kế hoạch ước tính cho các báo cáo vấn đề có toán tử song song không? Nếu có, bạn có thể kiểm tra xem sự cố xảy ra mà không có sự song song tức là với gợi ý MAXDOP = 1.
Amit Banerjee

2
Mã trông ổn, ngoại trừ [SqlFunction]thuộc tính trùng lặp . Đó có phải là mã chính xác? Tôi không nghĩ rằng nó sẽ được biên dịch. Phân biệt phiên bản Framework 2.0 / 3.0 / 3.5 không phải là vấn đề vì bạn đang sử dụng 4.0 / 4.5 / 4.5.x / etc hoặc bất cứ thứ gì trên máy chủ đó vì bạn đang ở trên SQL Server 2014 bị ràng buộc với phiên bản CLR 4. Đây có phải là Máy chủ hiển thị vấn đề 32-bit? Nó có bao nhiêu bộ nhớ so với các máy chủ khác? Và bạn đã kiểm tra nhật ký SQL Server ngay sau khi gặp lỗi đó chưa?
Solomon Rutzky

2
Phiên bản chính xác của .NET không liên quan đến sự cố, mặc dù vậy sẽ rất tốt nếu biết tất cả các máy chủ có trên ít nhất 4,5 vì điều đó có nghĩa là bạn có thể sử dụng thuộc tính mới MatchTimeout. Nhưng tôi không nghĩ đó thực sự là vấn đề nếu bạn chỉ đạt tối đa 5 ký tự. Đó có thể là một máy tính này có hỏng cài đặt của .NET Framework, và có thể được sửa chữa một lần cá hồi hoạt động khai thác đã ngừng ;-). Ngoài ra, [0-9].*đơn giản nhưng cũng không hiệu quả vì nó phù hợp với tất cả các ký tự, nếu có, sau chữ số đầu tiên; sử dụng chỉ [0-9]cho một IsMatchlà tốt hơn.
Solomon Rutzky

1
Tại sao bạn đổi DataAccessKindthành Read? Điều đó chỉ làm chậm nó và bạn không thực hiện bất kỳ truy cập dữ liệu. Ngoài ra, tôi nhận ra rằng nó dường như đang hoạt động, nhưng tôi sẽ thận trọng với việc sử dụng ToString()phương pháp trái ngược với Valuetài sản vì tôi không nghĩ ToString xử lý mã hóa đúng cách, hoặc đại loại như thế. Đối chiếu cơ sở dữ liệu của bạn được đặt là gì? Tất nhiên, tôi chỉ đọc lại một trong những bình luận của bạn ở trên và thấy rằng cột là VARCHAR thay vì NVARCHAR. Liệu lĩnh vực đó có một đối chiếu khác với cơ sở dữ liệu?
Solomon Rutzky

Câu trả lời:


4

Vấn đề là xung đột cục bộ giữa HĐH Windows và SQL Server (cụ thể là cơ sở dữ liệu nơi hội được tải). Bạn có thể chạy truy vấn sau để xem cả hai đều được đặt thành:

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

Nếu chúng khác nhau thì bạn chắc chắn có thể có một số hành vi "kỳ quặc", chẳng hạn như những gì bạn đang thấy. Vấn đề là:

  • SqlStringbao gồm nhiều hơn chỉ bản thân văn bản: nó bao gồm đối chiếu mặc định của cơ sở dữ liệu trong đó tập hợp tồn tại. Đối chiếu bao gồm hai phần thông tin: thông tin ngôn ngữ (ví dụ LCID) và các tùy chọn so sánh (ví dụ SqlCompareOptions) mô tả chi tiết độ nhạy đối với trường hợp, dấu, kana, chiều rộng hoặc mọi thứ (nhị phân và nhị phân2).
  • Các hoạt động chuỗi trong .NET, trừ khi được cung cấp một miền rõ ràng, sử dụng thông tin ngôn ngữ của luồng hiện tại, được đặt trong Windows (tức là Hệ điều hành / HĐH).

Xung đột thường xảy ra khi tham chiếu tham số SqlString mà không sử dụng .Valuehoặc .ToString()do đó nó thực hiện chuyển đổi ngầm định SqlString. Trong trường hợp đó, nó sẽ gây ra một ngoại lệ nói rằng LCID không khớp.

Rõ ràng có các kịch bản khác, chẳng hạn như so sánh chuỗi thực hiện (một số / tất cả?), Bao gồm cả khi sử dụng Regex như trường hợp này cho thấy (mặc dù cho đến nay tôi vẫn chưa thể tái tạo điều này).

Một số ý tưởng để sửa lỗi:

Lý tưởng (kỳ vọng sẽ luôn được đáp ứng về cách so sánh hoạt động):

  • Thay đổi LCID Windows hoặc SQL Server (ngôn ngữ mặc định) để cả hai khớp nhau

Ít hơn lý tưởng (hành vi của ngôn ngữ Windows có thể không phải là các quy tắc giống nhau cho sự bình đẳng và sắp xếp và do đó có thể có kết quả không mong muốn):

  • Sử dụng .ToStringphương thức hoặc thuộc .Valuetính, cả hai đều trả về chuỗi mà không có SQL Server LCID, vì vậy tất cả các hoạt động sẽ được sử dụng LCID OS.

Có thể giúp:

  • Có thể sử dụng SqlCharsthay vì vì SqlStringnó không mang theo LCID và thông tin đối chiếu từ SQL Server
  • Chỉ định rằng văn hóa không quan trọng thông qua StringComparison.InvariantCulture:
    • String.Compare(string, string, StringComparison.InvariantCulture) hoặc là String.Compare(string, string, StringComparison.InvariantCultureIgnoreCase)
    • Đối với Regex, chỉ định RegexOptions.CultureInvariant

1

Đã cập nhật ..

Bản địa hóa khác nhau giữa SQL Engine và window Server khi @srutzky chỉ ra:

os_l Language_version SqlServerLCID
1033 1039

Thay đổi sau đây đối với mã - cài đặt tùy chọn RegexOptions.CultureInvariantbị lỗi. Mã không thay đổi sẽ không sập SQL Server 2012 trên Windows Server 2012R2 với cùng cài đặt ngôn ngữ nhưng thực hiện như vậy trên SQL Server 2014.

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

Bạn có thể vui lòng chạy như sau trên máy chủ bị lỗi : SELECT os_language_version, SERVERPROPERTY('LCID') AS 'SqlServerLCID' FROM sys.dm_os_windows_info;. Hoàn toàn có thể vấn đề là xung đột trong cài đặt ngôn ngữ. Giải pháp của bạn có thể vẫn là cách tốt nhất để đi, nhưng nhìn chung không nên sử dụng ToString()thay vì Valuetài sản trên SqlStrings. Vì vậy, nó sẽ chỉ là tốt đẹp để xác nhận tình hình.
Solomon Rutzky

Tôi đã đăng một câu trả lời để làm rõ, nhưng vấn đề không nên được giải quyết bằng cách thiết lập RegexOptions.CultureInvariantvì bạn không chuyển Optionsbiến vào Regex.IsMatch(sqldata, regex). Điều thay đổi giữa mã gốc của bạn và mã mới, mã làm việc là bạn đã chuyển từ sử dụng SqlString.Valuesang SqlString.ToString(). Tôi nghi ngờ bạn sẽ thấy hành vi cố định tương tự nếu bạn chuyển sang sử dụng SqlChars. Nhưng tôi sẽ chỉ làm điều đó như một bài kiểm tra. Cách tiếp cận tốt nhất là thay đổi LCID của Windows hoặc SQL Server để khớp với cái khác. Bạn cũng có thể loại bỏ biến tĩnh Tùy chọn.
Solomon Rutzky

Chào bạn Cảm ơn vì đã chấp nhận câu trả lời của tôi :). Chỉ cần đề cập, tôi đã nghiên cứu thêm và, nếu hiểu những gì tôi đang nhìn thấy, thì trong khi tôi chính xác về nguyên nhân gốc rễ là một LCID khác nhau giữa HĐH và SQL Server, thì nó không hoặc không nên liên quan đến .Valuetài sản của một SqlStringnhư vậy rõ ràng trả về cùng một giá trị nội bộ như .ToString()phương thức. Tôi vẫn đang điều tra và sẽ cập nhật câu trả lời của tôi với bất cứ điều gì tôi tìm thấy :).
Solomon Rutzky

Tôi điều chỉnh câu trả lời của tôi trong ánh sáng của thông tin mới. Tôi không thể tái tạo kịch bản này. Mã trong Câu hỏi có thực sự là những gì bạn đang / đang sử dụng không? Sự khác biệt thực sự duy nhất giữa chúng là cái mà lỗi sử dụng RegexOptions.IgnoreCasetrong khi cái kia thì không. Tôi đã thiết lập một môi trường tương tự: Windows (8.0) sử dụng LCID là 1033, SQL Server DB có LCID là 1039, sử dụng cùng một RegEx mà bạn đã đăng, thực hiện COUNT(*)trên một VARCHARtrường chứa đầy GUID, sử dụng mẫu của '[0-3â].*', trên bảng với 10 triệu hàng. Đó là SQL Server 2012, không phải 2014, mặc dù tôi không nghĩ đó là vấn đề.
Solomon Rutzky

1
Cảm ơn tất cả các câu trả lời. Mã trong câu hỏi là những gì tôi đã sử dụng. Tôi đã có một regex thực sự phức tạp nhưng đã cố gắng khắc phục điều này bằng cách sử dụng một cái rất đơn giản. Thay đổi cài đặt RegexOptions.CultInvariant đã dừng hành vi
Sporri
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.