简体   繁体   中英

How to improve the performance of a LINQ query

I have a query that calls from a view - TheSQLView - and joins on a table - TheSQLTable - to get a list of results from that view. If I were to get every single record from the view, there would be ~2000 results. That alone takes about 40 seconds to execute. Even if I use a where clause that would return 40 results, it still takes about 8 seconds.

Here is some code:

using (var db = new SQLEntities(_connStr))
{
   var query = from x in db.TheSQLView
               join y in db.TheSQLTable on x.ID equals y.ID
               select new BSTProject()
               {
                  ID = x.ID,
                  Name = x.Name,
                  ... snipped for brevity (about 12 more properties) ...
                  // The two joined properties
                  PctCompleted = y.PctCompleted == null ? 0 : y.PctCompleted,
                  IsCompleted = y.IsCompleted
               };

   return query.toList();
}

I'm assuming it might be something to do with joining the view on the table?

Edit 1: Ran the SQL Profiler and this query is what's being executed:

SELECT 
[Project1].[IsCompleted] AS [IsCompleted], 
[Project1].[ID] AS [ID], 
[Project1].[Name] AS [Name], 
[Project1].[org_code] AS [org_code], 
[Project1].[GroupName] AS [GroupName], 
[Project1].[clnt_name] AS [clnt_name], 
[Project1].[start_date] AS [start_date], 
[Project1].[PRIcode] AS [PRIcode], 
[Project1].[PRI] AS [PRI], 
[Project1].[PMcode] AS [PMcode], 
[Project1].[PM] AS [PM], 
[Project1].[DPMcode] AS [DPMcode], 
[Project1].[DPM] AS [DPM], 
[Project1].[ADMcode] AS [ADMcode], 
[Project1].[ADM] AS [ADM], 
[Project1].[PhaseBudgetsTotal] AS [PhaseBudgetsTotal], 
[Project1].[PhasesEffortTotal] AS [PhasesEffortTotal], 
[Project1].[PhasesBudgetRemaining] AS [PhasesBudgetRemaining], 
[Project1].[PhasesOver] AS [PhasesOver], 
[Project1].[C1] AS [C1]
FROM ( SELECT 
    [Extent1].[org_code] AS [org_code], 
    [Extent1].[GroupName] AS [GroupName], 
    [Extent1].[ID] AS [ID], 
    [Extent1].[Name] AS [Name], 
    [Extent1].[clnt_name] AS [clnt_name], 
    [Extent1].[start_date] AS [start_date], 
    [Extent1].[PRIcode] AS [PRIcode], 
    [Extent1].[PRI] AS [PRI], 
    [Extent1].[PMcode] AS [PMcode], 
    [Extent1].[PM] AS [PM], 
    [Extent1].[DPMcode] AS [DPMcode], 
    [Extent1].[DPM] AS [DPM], 
    [Extent1].[ADMcode] AS [ADMcode], 
    [Extent1].[ADM] AS [ADM], 
    [Extent1].[PhaseBudgetsTotal] AS [PhaseBudgetsTotal], 
    [Extent1].[PhasesEffortTotal] AS [PhasesEffortTotal], 
    [Extent1].[PhasesBudgetRemaining] AS [PhasesBudgetRemaining], 
    [Extent1].[PhasesOver] AS [PhasesOver], 
    [Extent2].[IsCompleted] AS [IsCompleted], 
    CASE WHEN ([Extent2].[PctCompleted] IS NULL) THEN cast(0 as decimal(18)) ELSE [Extent2].[PctCompleted] END AS [C1]
    FROM  (SELECT 
[TheSQLView].[org_code] AS [org_code], 
[TheSQLView].[GroupName] AS [GroupName], 
[TheSQLView].[ID] AS [ID], 
[TheSQLView].[Name] AS [Name], 
[TheSQLView].[clnt_name] AS [clnt_name], 
[TheSQLView].[start_date] AS [start_date], 
[TheSQLView].[PRIcode] AS [PRIcode], 
[TheSQLView].[PRI] AS [PRI], 
[TheSQLView].[PMcode] AS [PMcode], 
[TheSQLView].[PM] AS [PM], 
[TheSQLView].[DPMcode] AS [DPMcode], 
[TheSQLView].[DPM] AS [DPM], 
[TheSQLView].[ADMcode] AS [ADMcode], 
[TheSQLView].[ADM] AS [ADM], 
[TheSQLView].[PhaseBudgetsTotal] AS [PhaseBudgetsTotal], 
[TheSQLView].[PhasesEffortTotal] AS [PhasesEffortTotal], 
[TheSQLView].[PhasesBudgetRemaining] AS [PhasesBudgetRemaining], 
[TheSQLView].[PhasesOver] AS [PhasesOver]
FROM [dbo].[TheSQLView] AS [TheSQLView]) AS [Extent1]
    INNER JOIN (SELECT 
[TheSQLTable].[ID] AS [ID], 
[TheSQLTable].[IsCompleted] AS [IsCompleted], 
[TheSQLTable].[PctCompleted] AS [PctCompleted]
FROM [dbo].[TheSQLTable] AS [TheSQLTable]) AS [Extent2] ON [Extent1].[ID] = [Extent2].[ID]
)  AS [Project1]
ORDER BY [Project1].[ID] ASC

There is precious little info in your question. The generated SQL is nice, but it would be even nicer had you also posted the cpu + logical read counters from SQL Profiler.

But, I will take a wild stab at an answer: Look into indexed views (a clustered index no less). I strongly suspect your view doesn't have one. Look here for some links to get you going: https://stackoverflow.com/a/3986540/1736944

One caveat: If you are not using the Enterprise edition of SQL Server, then your query must contain the "WITH (NOEXPAND)" hint. Simply create a second view that selects all rows from the first view and refer to this second view in your EF query. Confirm with SQL Profiler + query plan that you get a reasonable query plan.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM