Linq to SQL:查询在SQL Server Management Studio中运行良好,但在应用程序上超时

时间:2016-01-25 17:41:58

标签: c# sql-server linq linq-to-sql legacy

我维护遗留应用程序的代码。它正在使用Entity Framework 3.5,目前无法将其更新为更新版本。

最近有一个查询已经开始超时。这是LINQ中的查询:

var compoQueryResult = (from composition in MyAppDataContext.Compositions
                            join compositionStatus in MyAppDataContext.CompositionStatus on composition.StatusID equals compositionStatus.CompositionStatusID
                            join compoUnit in MyAppDataContext.CompositionUnits on composition.CompositionID equals compoUnit.CompositionID
                            join unit in MyAppDataContext.Units on compoUnit.UnitID equals unit.UnitID
                            join carUnit in MyAppDataContext.Car_Units on unit.UnitID equals carUnit.UnitId
                            join car in MyAppDataContext.Cars on carUnit.CarId equals car.CarID
                            join location in MyAppDataContext.Locations on unit.ParkedLocationID equals location.LocationID
                            from road in MyAppDataContext.Roads.Where(r => r.RoadID == unit.RoadID).DefaultIfEmpty()
                            from ta in MyAppDataContext.Allocations.Where(ta => ta.CompositionId == composition.CompositionID).DefaultIfEmpty()
                            from arrivalLocation in MyAppDataContext.Locations.Where(al => al.LocationID == ta.EndLocationID).DefaultIfEmpty()
                            where (MyApp.IsAdministrator || MyApp.GetLineIds().Contains(car.LineId.Value))
                            && car.LineId.Value == LineId                           
                            && (statusId == null || statusId == compositionStatus.CompositionStatusID)
                            && (locationId == null || unit.ParkedLocationID == locationId)
                            && (!onlyATMS.HasValue
                                 || (onlyATMS == true && composition.CompositionName.Contains(Common.Constants.ATMSSymbol))
                                 || (onlyATMS == false && !composition.CompositionName.Contains(Common.Constants.ATMSSymbol)))
                            select new CompositionQueryResultItem
                            {
                                CompositionId = composition.CompositionID,
                                CompositionName = composition.CompositionName,
                                CompositionNumber = composition.CompositionNumber,
                                DateTimeModified = composition.DataModified,
                                Status = compositionStatus.CompositionStatusDesc,
                                Location = location.LocationName,
                                Road = road.Name,
                                Number = ta.Number,
                                DepartureTime = ta.DepartTime,
                                ArrivalLocation = arrivalLocation.LocationName,
                                ArrivalTime = ta.ArriveTime
                            }).Distinct().ToList();

调试应用程序后,我可以看到正在执行以下查询:

SELECT DISTINCT [t10].[CompositionID] AS [CompositionId], [t10].[CompositionName], [t10].[CompositionNumber], [t10].[value] AS [DateTimeModified], [t10].[CompositionStatusDesc] AS [Status], [t10].[LocationName] AS [Location], [t10].[value2] AS [Road], [t10].[value3] AS [Number], [t10].[value4] AS [DepartureTime], [t10].[value5] AS [ArrivalLocation], [t10].[value6] AS [ArrivalTime]
FROM (
    SELECT [t0].[CompositionID], [t0].[CompositionName], [t0].[CompositionNumber], [t0].[DataModified] AS [value], [t1].[CompositionStatusDesc], [t6].[LocationName], [t7].[Name] AS [value2], [t8].[Number] AS [value3], [t8].[DepartTime] AS [value4], [t9].[LocationName] AS [value5], [t8].[ArriveTime] AS [value6], [t5].[LineId]
    FROM [dbo].[Composition] AS [t0]
    INNER JOIN [dbo].[CompositionStatus] AS [t1] ON [t0].[StatusID] = [t1].[CompositionStatusID]
    INNER JOIN [dbo].[CompositionUnit] AS [t2] ON [t0].[CompositionID] = [t2].[CompositionID]
    INNER JOIN [dbo].[Unit] AS [t3] ON [t2].[UnitID] = [t3].[UnitID]
    INNER JOIN [dbo].[Car_Unit] AS [t4] ON [t3].[UnitID] = [t4].[UnitId]
    INNER JOIN [dbo].[Car] AS [t5] ON [t4].[CarId] = [t5].[CarID]
    INNER JOIN [dbo].[Location] AS [t6] ON [t3].[ParkedLocationID] = ([t6].[LocationID])
    LEFT OUTER JOIN [dbo].[Road] AS [t7] ON ([t7].[RoadID]) = [t3].[RoadID]
    LEFT OUTER JOIN [dbo].[Allocation] AS [t8] ON [t8].[CompositionId] = ([t0].[CompositionID])
    LEFT OUTER JOIN [dbo].[Location] AS [t9] ON [t9].[LocationID] = [t8].[EndLocationID]
    ) AS [t10]
WHERE ([t10].[LineId]) = @p0

如果我在SQL Server Manager Studio上执行该查询,则根本不会遇到任何问题。它在不到一秒的时间内执行。但是,应用程序已超时,我不知道为什么。

我试过

MyAppDataContext.ObjectTrackingEnabled = false;

但我仍然得到同样的错误。

我即将放弃并创建一个存储过程,但我无法理解超时发生的原因。

1 个答案:

答案 0 :(得分:0)

当通过应用程序运行相同的查询时,SQL Server使用的查询执行计划可能会有所不同。检查您的执行计划。您可以在查询结束时使用诸如option(recompile)之类的提示,也可以针对特定的Lineid优化它(如果对于不同的id,返回的行明显不同)。 有时,使用此类提示会使SSMS变慢,但在应用程序中却不会变慢。经过一番尝试后,您可以找到解决方案。