提高linq查询效率
Increase linq query effieciency
我正在优化我的 Web 应用程序,运行 遇到瓶颈,其中从我的 linq 表达式生成的 SQL 非常慢。
以下 SQL 执行时间不到一秒:
SELECT
ISNULL(COUNT(distinct JOBIDNumber),0),
ISNULL(SUM(JIMQuantityActual * JIMNetMarginFactor),0),
ISNULL(sum((isnull(MATRecoverablePercent,0) / 100) * JIMQuantityActual * JIMNetMarginFactor),0),
ISNULL(sum(CarbonSaving),0)
FROM
dbo.fn_GetJobsForUser(183486) jb
inner join cd_JobMaterial on JIMJobId = jb.JOBIDNumber
WHERE
JOBCollectionDate >= '2014-11-01'
而以下查询的 sql 输出对相同的数据需要 4 到 16 秒:
DateTime d = new DateTime(2014, 11, 1)
from job in sp.sp_GetJobsForUser(183486)
where job.JOBCollectionDate >= d
join material in UnitOfWork.Repository<cd_JobMaterial>().Queryable()
on job.JOBIDNumber equals material.JIMJobId
group material by 1 into f
select new
{
Jobs = f.Distinct().Count(),
Weight = f.Sum(x=> x.JIMQuantityActual * x.JIMNetMarginFactor),
Carbon = f.Sum(x=> x.CarbonSaving),
Recovery = f.Sum(x => ((x.MATRecoverablePercent / 100) * x.JIMQuantityActual * x.JIMNetMarginFactor))
}
输出如下:
-- Region Parameters
DECLARE @contactId Int = 183486
DECLARE @p__linq__0 DateTime2 = '2014-11-01 00:00:00.0000000'
-- EndRegion
SELECT
[Project4].[C1] AS [C1],
[Project4].[C5] AS [C2],
[Project4].[C2] AS [C3],
[Project4].[C3] AS [C4],
[Project4].[C4] AS [C5]
FROM (SELECT
[Project2].[C1] AS [C1],
[Project2].[C2] AS [C2],
[Project2].[C3] AS [C3],
[Project2].[C4] AS [C4],
(SELECT
COUNT(1) AS [A1]
FROM (SELECT DISTINCT
/*Fields omitted for brevity */
FROM [dbo].[fn_GetJobsForUser](@contactId) AS [Extent3]
INNER JOIN (SELECT
/*Fields omitted for brevity */
FROM [dbo].[cd_JobMaterial] AS [cd_JobMaterial]) AS [Extent4]
ON [Extent3].[JOBIDNumber] = [Extent4].[JIMJobId]
WHERE ([Extent3].[JOBCollectionDate] >= @p__linq__0)
AND ([Project2].[C1] = 1)) AS [Distinct1])
AS [C5]
FROM (SELECT
@contactId AS [contactId],
@p__linq__0 AS [p__linq__0],
[GroupBy1].[K1] AS [C1],
[GroupBy1].[A1] AS [C2],
[GroupBy1].[A2] AS [C3],
[GroupBy1].[A3] AS [C4]
FROM (SELECT
[Project1].[K1] AS [K1],
SUM([Project1].[A1]) AS [A1],
SUM([Project1].[A2]) AS [A2],
SUM([Project1].[A3]) AS [A3]
FROM (SELECT
1 AS [K1],
[Project1].[JIMQuantityActual] * [Project1].[JIMNetMarginFactor] AS [A1],
[Project1].[CarbonSaving] AS [A2],
([Project1].[MATRecoverablePercent] / CAST(100 AS DECIMAL(18))) * [Project1].[JIMQuantityActual] * [Project1].[JIMNetMarginFactor] AS [A3]
FROM (SELECT
[Extent2].[MATRecoverablePercent] AS [MATRecoverablePercent],
[Extent2].[JIMQuantityActual] AS [JIMQuantityActual],
[Extent2].[JIMNetMarginFactor] AS [JIMNetMarginFactor],
[Extent2].[CarbonSaving] AS [CarbonSaving]
FROM [dbo].[fn_GetJobsForUser](@contactId) AS [Extent1]
INNER JOIN (SELECT
/*Fields omitted for brevity */
FROM [dbo].[cd_JobMaterial] AS [cd_JobMaterial]) AS [Extent2]
ON [Extent1].[JOBIDNumber] = [Extent2].[JIMJobId]
WHERE [Extent1].[JOBCollectionDate] >= @p__linq__0) AS [Project1]) AS [Project1]
GROUP BY [K1]) AS [GroupBy1]) AS [Project2]) AS [Project4]
如何重写 linq 表达式以产生更高效的结果 sql 还是只是编写存储过程并使用它来代替?
不幸的是,这是使用像 Entity Framework 这样灵活的东西的缺点之一,它必须支持各种复杂的翻译。不过,它显然在其他方面也有很大好处,因此您必须在这些方面与性能方面取得平衡。
即使您现在可以找到一种方法来重写生成更好的查询 SQL ,但在未来的版本中,基础提供程序可能会发生变化。在您的 应用程序的性能不再可接受之前,尽可能长时间地享受干净、简洁的代码。如果 EF 在那个时候没有削减它,那么使用提供的一些挂钩来执行原始 SQL、存储过程等,这不会那么漂亮。
我正在优化我的 Web 应用程序,运行 遇到瓶颈,其中从我的 linq 表达式生成的 SQL 非常慢。
以下 SQL 执行时间不到一秒:
SELECT
ISNULL(COUNT(distinct JOBIDNumber),0),
ISNULL(SUM(JIMQuantityActual * JIMNetMarginFactor),0),
ISNULL(sum((isnull(MATRecoverablePercent,0) / 100) * JIMQuantityActual * JIMNetMarginFactor),0),
ISNULL(sum(CarbonSaving),0)
FROM
dbo.fn_GetJobsForUser(183486) jb
inner join cd_JobMaterial on JIMJobId = jb.JOBIDNumber
WHERE
JOBCollectionDate >= '2014-11-01'
而以下查询的 sql 输出对相同的数据需要 4 到 16 秒:
DateTime d = new DateTime(2014, 11, 1)
from job in sp.sp_GetJobsForUser(183486)
where job.JOBCollectionDate >= d
join material in UnitOfWork.Repository<cd_JobMaterial>().Queryable()
on job.JOBIDNumber equals material.JIMJobId
group material by 1 into f
select new
{
Jobs = f.Distinct().Count(),
Weight = f.Sum(x=> x.JIMQuantityActual * x.JIMNetMarginFactor),
Carbon = f.Sum(x=> x.CarbonSaving),
Recovery = f.Sum(x => ((x.MATRecoverablePercent / 100) * x.JIMQuantityActual * x.JIMNetMarginFactor))
}
输出如下:
-- Region Parameters
DECLARE @contactId Int = 183486
DECLARE @p__linq__0 DateTime2 = '2014-11-01 00:00:00.0000000'
-- EndRegion
SELECT
[Project4].[C1] AS [C1],
[Project4].[C5] AS [C2],
[Project4].[C2] AS [C3],
[Project4].[C3] AS [C4],
[Project4].[C4] AS [C5]
FROM (SELECT
[Project2].[C1] AS [C1],
[Project2].[C2] AS [C2],
[Project2].[C3] AS [C3],
[Project2].[C4] AS [C4],
(SELECT
COUNT(1) AS [A1]
FROM (SELECT DISTINCT
/*Fields omitted for brevity */
FROM [dbo].[fn_GetJobsForUser](@contactId) AS [Extent3]
INNER JOIN (SELECT
/*Fields omitted for brevity */
FROM [dbo].[cd_JobMaterial] AS [cd_JobMaterial]) AS [Extent4]
ON [Extent3].[JOBIDNumber] = [Extent4].[JIMJobId]
WHERE ([Extent3].[JOBCollectionDate] >= @p__linq__0)
AND ([Project2].[C1] = 1)) AS [Distinct1])
AS [C5]
FROM (SELECT
@contactId AS [contactId],
@p__linq__0 AS [p__linq__0],
[GroupBy1].[K1] AS [C1],
[GroupBy1].[A1] AS [C2],
[GroupBy1].[A2] AS [C3],
[GroupBy1].[A3] AS [C4]
FROM (SELECT
[Project1].[K1] AS [K1],
SUM([Project1].[A1]) AS [A1],
SUM([Project1].[A2]) AS [A2],
SUM([Project1].[A3]) AS [A3]
FROM (SELECT
1 AS [K1],
[Project1].[JIMQuantityActual] * [Project1].[JIMNetMarginFactor] AS [A1],
[Project1].[CarbonSaving] AS [A2],
([Project1].[MATRecoverablePercent] / CAST(100 AS DECIMAL(18))) * [Project1].[JIMQuantityActual] * [Project1].[JIMNetMarginFactor] AS [A3]
FROM (SELECT
[Extent2].[MATRecoverablePercent] AS [MATRecoverablePercent],
[Extent2].[JIMQuantityActual] AS [JIMQuantityActual],
[Extent2].[JIMNetMarginFactor] AS [JIMNetMarginFactor],
[Extent2].[CarbonSaving] AS [CarbonSaving]
FROM [dbo].[fn_GetJobsForUser](@contactId) AS [Extent1]
INNER JOIN (SELECT
/*Fields omitted for brevity */
FROM [dbo].[cd_JobMaterial] AS [cd_JobMaterial]) AS [Extent2]
ON [Extent1].[JOBIDNumber] = [Extent2].[JIMJobId]
WHERE [Extent1].[JOBCollectionDate] >= @p__linq__0) AS [Project1]) AS [Project1]
GROUP BY [K1]) AS [GroupBy1]) AS [Project2]) AS [Project4]
如何重写 linq 表达式以产生更高效的结果 sql 还是只是编写存储过程并使用它来代替?
不幸的是,这是使用像 Entity Framework 这样灵活的东西的缺点之一,它必须支持各种复杂的翻译。不过,它显然在其他方面也有很大好处,因此您必须在这些方面与性能方面取得平衡。
即使您现在可以找到一种方法来重写生成更好的查询 SQL ,但在未来的版本中,基础提供程序可能会发生变化。在您的 应用程序的性能不再可接受之前,尽可能长时间地享受干净、简洁的代码。如果 EF 在那个时候没有削减它,那么使用提供的一些挂钩来执行原始 SQL、存储过程等,这不会那么漂亮。