2014-09-19 97 views
5

我首先使用實體​​代碼。 索引列:linq to sql startwith性能索引列

  • SourceCatalogId
  • 殘疾人
  • CategoryPath

40 000表中的行,

我的問題是,查詢需要40秒!通過SQL事件探查器

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:

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

在之前的最後一個where子句,如果我刪除 「逃生N '' 〜 ''」:

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

查詢需要4s。

這是正常的嗎?索引用途?我可以用startWith解決它嗎?

編輯

爲categoryPath指數attribut:

[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(); 

=> SELECT [Extent1] [用戶ID] AS [用戶ID], [Extent1]。[名稱] AS [名稱] FROM [DBO]。[用戶] AS [Extent1] WHERE [Extent1]。[名稱] LIKE @ p__linq__0 ESCAPE N '〜'

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

=> SELECT [Extent1] [用戶ID] AS [用戶ID], [Extent1]。[名稱] AS [名稱] FROM [dbo]。[Users] AS [Extent1] WHERE [Extent1]。[Name] LIKE N'julien%'

因此,如果我在查詢中使用變量獲取存儲過程,如果使用const我得到選擇。

在存儲過程(由實體產生)使得出現@ p__linq__0所以加ESCAPE N '〜' 避免wildCaractere在變量。

所以現在的問題是簡單的。如何避免與變量查詢?這是可能的 ? 謝謝

+0

只要找到這篇文章,但不明白是否有任何解決方案? http://stackoverflow.com/questions/20496098/sql-generated-by-entityframework-startswith-contains-plan-altering-escape – Julian50 2014-09-19 10:25:49

+1

你使用全文索引,或只是正常索引(這不會幫助你部分字符串匹配)? – Mashton 2014-09-19 10:42:27

+0

@Mashton我不明白你的問題,但這是我如何使用代碼索引第一次編輯 – Julian50 2014-09-19 10:47:40

回答

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 2014-09-19 16:28:15

+0

WTF?所有代碼只是在查詢中包含一個Contains或StartWIth?如果沒有這個,執行起來太慢了。 – Arcadian 2015-02-19 21:29:27

+0

如何將這個與LINQ用於對象?它給我錯誤 – Arcadian 2015-02-19 21:51:19