2014-09-19 3 views
5

Сначала я использую код сущности. индексированных столбцов:linq to sql startwith performance индексированные столбцы

  • SourceCatalogId
  • Выключено
  • CategoryPath

40 000 строк в таблице,

Моя проблема запрос принимает 40s !!

var result = DBContext.Set<SourceProduct>() 
      .Include(x => x.SalesHistories, x => x.SourceCatalog) 
      .Where(p => p.SourceCatalogId == 2) 
      .where(p => p.Disabled == false) 
      .where(x => x.CategoryPath.StartsWith("MyPath")) 
      .orderby(x => x.ShortDesignation) 
      .Skip(1) 
      .Take(10) 
      .toList(); 

SQL с помощью SQL Profiler:

exec sp_executesql N'SELECT TOP (10) 
[Project1].[SourceProductId] AS [SourceProductId], 
[Project1].[SourceSKU] AS [SourceSKU], 
[Project1].[SourceCatalogId] AS [SourceCatalogId], 
[Project1].[ManufacturerReference] AS [ManufacturerReference], 
[Project1].[Disabled] AS [Disabled], 
[Project1].[EAN] AS [EAN], 
[Project1].[ShortDesignation] AS [ShortDesignation], 
[Project1].[FullDesignation] AS [FullDesignation], 
[Project1].[Description] AS [Description], 
[Project1].[Url] AS [Url], 
[Project1].[CategoryPath] AS [CategoryPath], 
[Project1].[Condition] AS [Condition], 
[Project1].[BuyingPriceHT] AS [BuyingPriceHT], 
[Project1].[ShippingPriceHT] AS [ShippingPriceHT], 
[Project1].[PublicSellingPriceHT] AS [PublicSellingPriceHT], 
[Project1].[PictureUrl1] AS [PictureUrl1], 
[Project1].[PictureUrl2] AS [PictureUrl2], 
[Project1].[PictureUrl3] AS [PictureUrl3], 
[Project1].[PictureUrl4] AS [PictureUrl4], 
[Project1].[Quantity] AS [Quantity], 
[Project1].[AddDate] AS [AddDate], 
[Project1].[UpdateDate] AS [UpdateDate], 
[Project1].[Followers] AS [Followers] 
FROM (SELECT [Project1].[SourceProductId] AS [SourceProductId], [Project1].[SourceSKU] AS [SourceSKU], [Project1].[SourceCatalogId] AS [SourceCatalogId], [Project1].[ManufacturerReference] AS [ManufacturerReference], [Project1].[Disabled] AS [Disabled], [Project1].[EAN] AS [EAN], [Project1].[ShortDesignation] AS [ShortDesignation], [Project1].[FullDesignation] AS [FullDesignation], [Project1].[Description] AS [Description], [Project1].[Url] AS [Url], [Project1].[CategoryPath] AS [CategoryPath], [Project1].[Condition] AS [Condition], [Project1].[BuyingPriceHT] AS [BuyingPriceHT], [Project1].[ShippingPriceHT] AS [ShippingPriceHT], [Project1].[PublicSellingPriceHT] AS [PublicSellingPriceHT], [Project1].[PictureUrl1] AS [PictureUrl1], [Project1].[PictureUrl2] AS [PictureUrl2], [Project1].[PictureUrl3] AS [PictureUrl3], [Project1].[PictureUrl4] AS [PictureUrl4], [Project1].[Quantity] AS [Quantity], [Project1].[AddDate] AS [AddDate], [Project1].[UpdateDate] AS [UpdateDate], [Project1].[Followers] AS [Followers], row_number() OVER (ORDER BY [Project1].[ShortDesignation] ASC) AS [row_number] 
    FROM (SELECT 
     [Extent1].[SourceProductId] AS [SourceProductId], 
     [Extent1].[SourceSKU] AS [SourceSKU], 
     [Extent1].[SourceCatalogId] AS [SourceCatalogId], 
     [Extent1].[ManufacturerReference] AS [ManufacturerReference], 
     [Extent1].[Disabled] AS [Disabled], 
     [Extent1].[EAN] AS [EAN], 
     [Extent1].[ShortDesignation] AS [ShortDesignation], 
     [Extent1].[FullDesignation] AS [FullDesignation], 
     [Extent1].[Description] AS [Description], 
     [Extent1].[Url] AS [Url], 
     [Extent1].[CategoryPath] AS [CategoryPath], 
     [Extent1].[Condition] AS [Condition], 
     [Extent1].[BuyingPriceHT] AS [BuyingPriceHT], 
     [Extent1].[ShippingPriceHT] AS [ShippingPriceHT], 
     [Extent1].[PublicSellingPriceHT] AS [PublicSellingPriceHT], 
     [Extent1].[PictureUrl1] AS [PictureUrl1], 
     [Extent1].[PictureUrl2] AS [PictureUrl2], 
     [Extent1].[PictureUrl3] AS [PictureUrl3], 
     [Extent1].[PictureUrl4] AS [PictureUrl4], 
     [Extent1].[Quantity] AS [Quantity], 
     [Extent1].[AddDate] AS [AddDate], 
     [Extent1].[UpdateDate] AS [UpdateDate], 
     [Extent1].[Followers] AS [Followers] 
     FROM [dbo].[SourceProducts] AS [Extent1] 
     WHERE ([Extent1].[SourceCatalogId] = @p__linq__0) AND (0 = [Extent1].[Disabled]) AND ([Extent1].[CategoryPath] LIKE @p__linq__1 ESCAPE N''~'') 
    ) AS [Project1] 
) AS [Project1] 
WHERE [Project1].[row_number] > 0 
ORDER BY [Project1].[ShortDesignation] ASC',N'@p__linq__0 bigint,@p__linq__1 nvarchar(4000)',@p__linq__0=2,@p__linq__1=N'MyPath%' 

В последнем перед где положение, если удалить "побег N '' ~ ''" в:

WHERE ([Extent1].[SourceCatalogId] = @p__linq__0) AND (0 = [Extent1].[Disabled]) AND ([Extent1].[CategoryPath] LIKE @p__linq__1 ESCAPE N''~'') 

запрос занимает 4 с.

Нормально ли это? Индекс использует? Как я могу решить это с помощью startWith?

EDIT

Индекс attribut для categoryPath:

[Index("IX_SourceProduct_SourceCatalogId_Disabled_CategoryPath", 3), StringLength(400)] 
    public string CategoryPath { get; set; } 

EDIT2

ОК я вещь, что я довольно близко, я думаю, что Probleme хранится процедура.

string search = "julien"; 
      var list = db.Users.Where(x => x.Name.StartsWith(search)); 
      string query = list.ToString(); 

=> ВЫБОР [Extent1]. [UserId] AS [UserId], [Extent1]. [Имя] [Имя] ОТ [DBO]. [Пользователи] AS [Extent1] Где [Extent1]. [Имя] как @ p__linq__0 ESCAPE N '~'

var list2 = db.Users.Where(x => x.Name.StartsWith("julien")); 
      string query2 = list2.ToString(); 

=> ВЫБОР [Extent1]. [USERID] С. [UserId], [Extent1]. [Имя] AS [Name] FROM [dbo]. [Users] AS [Extent1] WHERE [Extent1]. [Name] LIKE N'julien% '

Так что, если я использую переменную в запросе в получении хранимой процедуры, если я использую const Я получаю выбор.

В хранимой процедуре (генерируемой лица) делает появляются @ p__linq__0 поэтому добавьте ESCAPE N «~» , чтобы избежать wildCaractere в переменной.

Так что теперь вопрос проще. Как избежать запроса с переменной? возможно ? thanks

+0

Просто найдите это сообщение, но не понимайте, есть ли какое-либо решение? http://stackoverflow.com/questions/20496098/sql-generated-by-entityframework-startswith-contains-plan-altering-escape – Julian50

+1

Вы используете полнотекстовый индекс или просто нормальное индексирование (что не поможет вам с частичное совпадение строк)? – Mashton

+0

@Mashton Я не понимаю ваш вопрос, но это то, как я индексирую код, сначала вижу первый EDIT. – Julian50

ответ

4

Так что вам нужно сделать здесь, это взять значение переменной и использовать его как константу в Expression, который вы генерируете. Это на самом деле вполне возможно. Нам понадобится выражение, которое принимает параметр, который вы хотите как параметр вашего реального селектора, как второй параметр, который является заполнителем для значения константы, а затем значение, которое вы хотите быть константой. Затем мы можем заменить все экземпляры параметра со значением константы, оставив только функцию, которая отображает реальный параметр в результате:

public static Expression<Func<TSource, TResult>> EmbedConstant 
    <TSource, TResult, TConstant>(
    this Expression<Func<TSource, TConstant, TResult>> expression, 
    TConstant constant) 
{ 
    var body = expression.Body.Replace(
     expression.Parameters[1], 
     Expression.Constant(constant)); 
    return Expression.Lambda<Func<TSource, TResult>>(
     body, expression.Parameters[0]); 
} 

Это зависит от следующих методов для замены всех экземпляров одного выражения с другой:

public static Expression Replace(this Expression expression, 
    Expression searchEx, Expression replaceEx) 
{ 
    return new ReplaceVisitor(searchEx, replaceEx).Visit(expression); 
} 
internal class ReplaceVisitor : ExpressionVisitor 
{ 
    private readonly Expression from, to; 
    public ReplaceVisitor(Expression from, Expression to) 
    { 
     this.from = from; 
     this.to = to; 
    } 
    public override Expression Visit(Expression node) 
    { 
     return node == from ? to : base.Visit(node); 
    } 
} 

Это позволяет отображать это:

string search = "julien"; 
var list = db.Users.Where(x => x.Name.StartsWith(search)); 
string query = list.ToString(); 

в это:

string search = "julien"; 
Expression<Func<User, string, bool>> predicate = 
    (item, searchTerm) => item.Name.StartsWith(searchTerm); 
var list = db.Users.Where(predicate.EmbedConstant(search)); 
string query = list.ToString(); 
+0

Удивительно, что он работает !!! Один день потратил на это ... большое вам спасибо. Могу ли я предложить вам медведя;) (как мы говорим спасибо во Франции) – Julian50

+0

WTF? Все, что код просто для включения Содержит или StartWIth в запросе ??? и без этого .. это было бы очень медленным для выполнения. – Arcadian

+0

Как использовать это с LINQ для объекта? он дает мне ошибки – Arcadian