Số dư thừa ESCAPE
chắc chắn có thể thay đổi ước tính thẻ và đưa ra một kế hoạch khác. Mặc dù đủ vui vẻ tôi thấy nó làm cho nó chính xác hơn là ít hơn trong bài kiểm tra này!
CREATE TABLE T
(
Title VARCHAR(50),
ID INT IDENTITY,
Filler char(1) NULL,
UNIQUE NONCLUSTERED (Title, ID)
)
INSERT INTO T
(Title)
SELECT TOP 1000 CASE
WHEN ROW_NUMBER() OVER (ORDER BY @@SPID) < 10 THEN 'food'
ELSE LEFT(NEWID(), 10)
END
FROM master..spt_values
Without Escape
SELECT *
FROM T
WHERE (Title LIKE 'foo%')
Với Escape
SELECT *
FROM T
WHERE (Title LIKE 'foo%' ESCAPE '~')
Ngắn nâng cấp lên phiên bản EF mới hơn hoặc viết tùy chỉnh thực hiện DbProviderManifest
tùy chỉnh của riêng tôi Tôi nghĩ rằng bạn không may mắn khi cố gắng xóa ESCAPE
.
Dịch String.StartsWith
, String.EndsWith
và String.Contains
-LIKE
hơn CHARINDEX
được new in EF 4.0
Nhìn vào định nghĩa của System.Data.Entity, Version=4.0.0.0
trong phản xạ chức năng có liên quan có vẻ là (trong System.Data.SqlClient.SqlProviderManifest
)
public override string EscapeLikeArgument(string argument)
{
bool flag;
EntityUtil.CheckArgumentNull<string>(argument, "argument");
return EscapeLikeText(argument, true, out flag);
}
Chữ ký cho điều đó là
internal static string EscapeLikeText(string text,
bool alwaysEscapeEscapeChar,
out bool usedEscapeChar)
{
usedEscapeChar = false;
if (((!text.Contains("%") && !text.Contains("_")) && (!text.Contains("[") && !text.Contains("^"))) && (!alwaysEscapeEscapeChar || !text.Contains("~")))
{
return text;
}
StringBuilder builder = new StringBuilder(text.Length);
foreach (char ch in text)
{
switch (ch)
{
case '%':
case '_':
case '[':
case '^':
case '~':
builder.Append('~');
usedEscapeChar = true;
break;
}
builder.Append(ch);
}
return builder.ToString();
}
Vì vậy, nó chỉ là hardcoded để luôn luôn sử dụng thoát và lá cờ được trả về là bỏ qua.
Vì vậy, phiên bản EF đó chỉ thêm ESCAPE '~'
vào tất cả các truy vấn LIKE
.
Điều này có vẻ là một cái gì đó đã được cải thiện trong cơ sở mã gần đây nhất.
Định nghĩa của SqlFunctionCallHandler.TranslateConstantParameterForLike là
// <summary>
// Function to translate the StartsWith, EndsWith and Contains canonical functions to LIKE expression in T-SQL
// and also add the trailing ESCAPE '~' when escaping of the search string for the LIKE expression has occurred
// </summary>
private static void TranslateConstantParameterForLike(
SqlGenerator sqlgen, DbExpression targetExpression, DbConstantExpression constSearchParamExpression, SqlBuilder result,
bool insertPercentStart, bool insertPercentEnd)
{
result.Append(targetExpression.Accept(sqlgen));
result.Append(" LIKE ");
// If it's a DbConstantExpression then escape the search parameter if necessary.
bool escapingOccurred;
var searchParamBuilder = new StringBuilder();
if (insertPercentStart)
{
searchParamBuilder.Append("%");
}
searchParamBuilder.Append(
SqlProviderManifest.EscapeLikeText(constSearchParamExpression.Value as string, false, out escapingOccurred));
if (insertPercentEnd)
{
searchParamBuilder.Append("%");
}
var escapedSearchParamExpression = constSearchParamExpression.ResultType.Constant(searchParamBuilder.ToString());
result.Append(escapedSearchParamExpression.Accept(sqlgen));
// If escaping did occur (special characters were found), then append the escape character used.
if (escapingOccurred)
{
result.Append(" ESCAPE '" + SqlProviderManifest.LikeEscapeChar + "'");
}
}
SqlProviderManifest.EscapeLikeText là mã tương tự như đã được hiển thị. Lưu ý rằng nó bây giờ vượt qua false
làm thông số thứ hai và sử dụng cờ tham số đầu ra để chỉ chắp thêm ESCAPE
nếu cần.
Xin vui lòng gửi truy vấn đầy đủ chính xác như chặn bởi SQL Profiler. Có gì đó không đúng ở đây. Mệnh đề ESCAPE hợp lý không nên ảnh hưởng đến quyết định của trình tối ưu hóa. Tôi cũng không thể tái sản xuất: 'CHỌN * TỪ sys.objects WHERE name LIKE 'obj%' ESCAPE '~''. Btw, mệnh đề ESCAPE cho phép bạn thực thi StartsWith ("%") một cách chính xác. Nó là cần thiết. – usr
@usr - [Nó có thể ảnh hưởng đến ước tính số lượng thẻ] (http://connect.microsoft.com/SQLServer/feedback/details/680257/optimization-problem-on-a-query-with-two-similar-like-clauses- một-với-một-biến) 'Chúng tôi không có hỗ trợ cho ước tính chính xác về thẻ trong sự hiện diện của các ký tự thoát được xác định bởi người dùng. Vì vậy, chúng tôi có thể nhận được một ước tính kém và một kế hoạch kém. Chúng tôi sẽ xem xét giải quyết vấn đề này trong bản phát hành trong tương lai.' –
Câu hỏi cũng được trả lời tại đây: http://stackoverflow.com/questions/16935402/make-entity-framework-use-contains-instead-of-like-and- giải thích-thoát –