我一直在使用實體框架6代碼首先在我的域模型上執行一些簡單的CRUD操作,目前它的表現令人讚歎。替換由實體框架生成的慢SQL的選項6
我現在遇到了一個情況,我正在執行一個相當複雜的查詢,它涉及過濾和分頁結果。由EF 6生成的查詢非常糟糕,與我可以手動操作的東西相比,效率非常低。這裏生成的SQL,其執行在〜17秒:
SELECT TOP (15)
[Project1].[Branch] AS [Branch] ,
[Project1].[Salesman] AS [Salesman] ,
[Project1].[Status] AS [Status] ,
[Project1].[OrderID] AS [OrderID] ,
[Project1].[DateCreated] AS [DateCreated] ,
[Project1].[DateCompleted] AS [DateCompleted] ,
[Project1].[RegNumber] AS [RegNumber] ,
[Project1].[Make] AS [Make] ,
[Project1].[Model] AS [Model] ,
[Project1].[Spec] AS [Spec] ,
[Project1].[Title] AS [Title] ,
[Project1].[Firstname] AS [Firstname] ,
[Project1].[Surname] AS [Surname] ,
[Project1].[Address1] AS [Address1] ,
[Project1].[Address2] AS [Address2] ,
[Project1].[Address3] AS [Address3] ,
[Project1].[Town] AS [Town] ,
[Project1].[County] AS [County] ,
[Project1].[Postcode] AS [Postcode] ,
[Project1].[HomePhone] AS [HomePhone] ,
[Project1].[WorkPhone] AS [WorkPhone] ,
[Project1].[MobilePhone] AS [MobilePhone] ,
[Project1].[EMailAddress] AS [EMailAddress] ,
[Project1].[AllowMarketing] AS [AllowMarketing] ,
[Project1].[Manager] AS [Manager] ,
[Project1].[FK_BranchID] AS [FK_BranchID]
FROM (SELECT [Project1].[Branch] AS [Branch] ,
[Project1].[Salesman] AS [Salesman] ,
[Project1].[Status] AS [Status] ,
[Project1].[OrderID] AS [OrderID] ,
[Project1].[DateCreated] AS [DateCreated] ,
[Project1].[DateCompleted] AS [DateCompleted] ,
[Project1].[RegNumber] AS [RegNumber] ,
[Project1].[Make] AS [Make] ,
[Project1].[Model] AS [Model] ,
[Project1].[Spec] AS [Spec] ,
[Project1].[Title] AS [Title] ,
[Project1].[Firstname] AS [Firstname] ,
[Project1].[Surname] AS [Surname] ,
[Project1].[Address1] AS [Address1] ,
[Project1].[Address2] AS [Address2] ,
[Project1].[Address3] AS [Address3] ,
[Project1].[Town] AS [Town] ,
[Project1].[County] AS [County] ,
[Project1].[Postcode] AS [Postcode] ,
[Project1].[HomePhone] AS [HomePhone] ,
[Project1].[WorkPhone] AS [WorkPhone] ,
[Project1].[MobilePhone] AS [MobilePhone] ,
[Project1].[EMailAddress] AS [EMailAddress] ,
[Project1].[AllowMarketing] AS [AllowMarketing] ,
[Project1].[Manager] AS [Manager] ,
[Project1].[FK_BranchID] AS [FK_BranchID] ,
ROW_NUMBER() OVER (ORDER BY [Project1].[DateCreated] DESC) AS [row_number]
FROM (SELECT [Extent1].[Branch] AS [Branch] ,
[Extent1].[Salesman] AS [Salesman] ,
[Extent1].[Status] AS [Status] ,
[Extent1].[OrderID] AS [OrderID] ,
[Extent1].[DateCreated] AS [DateCreated] ,
[Extent1].[DateCompleted] AS [DateCompleted] ,
[Extent1].[RegNumber] AS [RegNumber] ,
[Extent1].[Make] AS [Make] ,
[Extent1].[Model] AS [Model] ,
[Extent1].[Spec] AS [Spec] ,
[Extent1].[Title] AS [Title] ,
[Extent1].[Firstname] AS [Firstname] ,
[Extent1].[Surname] AS [Surname] ,
[Extent1].[Address1] AS [Address1] ,
[Extent1].[Address2] AS [Address2] ,
[Extent1].[Address3] AS [Address3] ,
[Extent1].[Town] AS [Town] ,
[Extent1].[County] AS [County] ,
[Extent1].[Postcode] AS [Postcode] ,
[Extent1].[HomePhone] AS [HomePhone] ,
[Extent1].[WorkPhone] AS [WorkPhone] ,
[Extent1].[MobilePhone] AS [MobilePhone] ,
[Extent1].[EMailAddress] AS [EMailAddress] ,
[Extent1].[AllowMarketing] AS [AllowMarketing] ,
[Extent1].[Manager] AS [Manager] ,
[Extent1].[FK_BranchID] AS [FK_BranchID]
FROM (SELECT [vw_CS_OrderDetails].[Branch] AS [Branch] ,
[vw_CS_OrderDetails].[Salesman] AS [Salesman] ,
[vw_CS_OrderDetails].[Status] AS [Status] ,
[vw_CS_OrderDetails].[OrderID] AS [OrderID] ,
[vw_CS_OrderDetails].[DateCreated] AS [DateCreated] ,
[vw_CS_OrderDetails].[DateCompleted] AS [DateCompleted] ,
[vw_CS_OrderDetails].[RegNumber] AS [RegNumber] ,
[vw_CS_OrderDetails].[Make] AS [Make] ,
[vw_CS_OrderDetails].[Model] AS [Model] ,
[vw_CS_OrderDetails].[Spec] AS [Spec] ,
[vw_CS_OrderDetails].[Title] AS [Title] ,
[vw_CS_OrderDetails].[Firstname] AS [Firstname] ,
[vw_CS_OrderDetails].[Surname] AS [Surname] ,
[vw_CS_OrderDetails].[Address1] AS [Address1] ,
[vw_CS_OrderDetails].[Address2] AS [Address2] ,
[vw_CS_OrderDetails].[Address3] AS [Address3] ,
[vw_CS_OrderDetails].[Town] AS [Town] ,
[vw_CS_OrderDetails].[County] AS [County] ,
[vw_CS_OrderDetails].[Postcode] AS [Postcode] ,
[vw_CS_OrderDetails].[HomePhone] AS [HomePhone] ,
[vw_CS_OrderDetails].[WorkPhone] AS [WorkPhone] ,
[vw_CS_OrderDetails].[MobilePhone] AS [MobilePhone] ,
[vw_CS_OrderDetails].[EMailAddress] AS [EMailAddress] ,
[vw_CS_OrderDetails].[AllowMarketing] AS [AllowMarketing] ,
[vw_CS_OrderDetails].[Manager] AS [Manager] ,
[vw_CS_OrderDetails].[FK_BranchID] AS [FK_BranchID]
FROM [dbo].[vw_CS_OrderDetails] AS [vw_CS_OrderDetails]
) AS [Extent1]
WHERE UPPER([Extent1].[RegNumber]) LIKE '%SD59BBO%'
ESCAPE N'~'
) AS [Project1]
) AS [Project1]
WHERE [Project1].[row_number] > 0
ORDER BY [Project1].[DateCreated] DESC
這樣做的手搖版本是更小的方式,在不到一秒鐘內完成。
鑑於第一個查詢的可怕的低效率,有沒有什麼辦法可以影響EF 6在查詢中創建?
我可能不得不求助於存儲過程,有沒有什麼好的模式可以將EF代碼先存儲到存儲過程?
編輯:根據來自Wahid Bitar的請求,這裏是我用來創建上述SQL的LINQ。
var query = _dbSet
.Where(o => o.RegNumber.ToUpper().Contains(searchTerm))
.OrderByDescending(c => c.DateCreated)
.Skip(skip)
.Take(pageSize);
事實上它的一些輔助方法中,稍微散開,但是這主要是它。最終在query
上調用ToList()
,枚舉結果集。
編輯:根據要求手搖SQL:
SELECT *
FROM
(
SELECT ROW_NUMBER() OVER (ORDER BY DateCreated DESC) AS RowNum
,[Branch]
,[Salesman]
,[Status]
,[OrderID]
,[DateCreated]
,[DateCompleted]
,[RegNumber]
,[Make]
,[Model]
,[Spec]
,[Title]
,[Firstname]
,[Surname]
,[Address1]
,[Address2]
,[Address3]
,[Town]
,[County]
,[Postcode]
,[HomePhone]
,[WorkPhone]
,[MobilePhone]
,[EMailAddress]
,[AllowMarketing]
,[Manager]
,[FK_BranchID]
FROM [SalesmanOffice2].[dbo].[vw_CS_OrderDetails]
WHERE RegNumber LIKE '%SD59BBO%'
) AS NumberedRows
WHERE NumberedRows.RowNum BETWEEN 1 AND 15 ORDER BY RowNum
請問您可以添加您編寫的c#linq代碼以獲取此Sql查詢。 –
你的手動查詢是什麼樣的? – cadrell0
根據你的命名約定,看起來你是在視圖上運行它。我發現EF會添加所有列,即使它們不需要或映射到視圖的模型中。您可以通過直接點擊底層表來優化它。另外,這個視圖很可能沒有被索引,這是直接訪問表可能會改進性能的地方。在這樣一個簡單的查詢中,缺少索引是我看到EF在性能方面遙遙領先的唯一途徑。 –