如何让Entity Framework在SQL Server中生成低效的查询?

djc*_*n66 5 sql-server entity-framework wcf-data-services

我在EF 4.0中定义了一个基于视图的实体.该视图覆盖了一个包含大约1800万行数据的表.我已选择实体的4个确定性属性作为此实体的复合实体键.我通过OData WCF数据服务公开了对包含此视图的模型的访问.WCF数据服务设置为限制结果

config.SetEntitySetPageSize("*", 100)
Run Code Online (Sandbox Code Playgroud)

当我针对此视图进行基本查询时:

var fcbs = this.iBenchmarkCostContext.FtCostBenchmarks.ToArray();
Run Code Online (Sandbox Code Playgroud)

这是我在分析工具中看到的查询:

SELECT TOP (100) [Extent1].[MonthBeginDt]                     AS [MonthBeginDt],
                 [Extent1].[dmCostBenchmarkKey]               AS [dmCostBenchmarkKey],
                 [Extent1].[dmProductKey]                     AS [dmProductKey],
                 [Extent1].[IsImputedFlg]                     AS [IsImputedFlg],
                 [Extent1].[ProjectedCopayPerRxAmt]           AS [ProjectedCopayPerRxAmt],
                 [Extent1].[ProjectedPricePerQtyAmt]          AS [ProjectedPricePerQtyAmt],
                 [Extent1].[ProjectedQtyPerRxQty]             AS [ProjectedQtyPerRxQty],
                 [Extent1].[ProjectedRxCnt]                   AS [ProjectedRxCnt],
                 [Extent1].[AvgPriceRxAvgPriceQtyDenominator] AS [AvgPriceRxAvgPriceQtyDenominator],
                 [Extent1].[AvgQtyDenominator]                AS [AvgQtyDenominator],
                 [Extent1].[AvgCopayDenominator]              AS [AvgCopayDenominator],
                 [Extent1].[ProjectedTotalCostAmt]            AS [ProjectedTotalCostAmt],
                 [Extent1].[AllowedRxCnt]                     AS [AllowedRxCnt],
                 [Extent1].[CopayRxCnt]                       AS [CopayRxCnt],
                 [Extent1].[TotalAllowedAmt]                  AS [TotalAllowedAmt],
                 [Extent1].[TotalCopayAmt]                    AS [TotalCopayAmt],
                 [Extent1].[TotalCostPerUnitAmt]              AS [TotalCostPerUnitAmt],
                 [Extent1].[TotalUnitQty]                     AS [TotalUnitQty],
                 [Extent1].[RC]                               AS [RC]
FROM   (SELECT [ftCostBenchmark].[MonthBeginDt]                     AS [MonthBeginDt],
               [ftCostBenchmark].[dmCostBenchmarkKey]               AS [dmCostBenchmarkKey],
               [ftCostBenchmark].[dmProductKey]                     AS [dmProductKey],
               [ftCostBenchmark].[IsImputedFlg]                     AS [IsImputedFlg],
               [ftCostBenchmark].[ProjectedCopayPerRxAmt]           AS [ProjectedCopayPerRxAmt],
               [ftCostBenchmark].[ProjectedPricePerQtyAmt]          AS [ProjectedPricePerQtyAmt],
               [ftCostBenchmark].[ProjectedQtyPerRxQty]             AS [ProjectedQtyPerRxQty],
               [ftCostBenchmark].[ProjectedRxCnt]                   AS [ProjectedRxCnt],
               [ftCostBenchmark].[AvgPriceRxAvgPriceQtyDenominator] AS [AvgPriceRxAvgPriceQtyDenominator],
               [ftCostBenchmark].[AvgQtyDenominator]                AS [AvgQtyDenominator],
               [ftCostBenchmark].[AvgCopayDenominator]              AS [AvgCopayDenominator],
               [ftCostBenchmark].[ProjectedTotalCostAmt]            AS [ProjectedTotalCostAmt],
               [ftCostBenchmark].[AllowedRxCnt]                     AS [AllowedRxCnt],
               [ftCostBenchmark].[CopayRxCnt]                       AS [CopayRxCnt],
               [ftCostBenchmark].[TotalAllowedAmt]                  AS [TotalAllowedAmt],
               [ftCostBenchmark].[TotalCopayAmt]                    AS [TotalCopayAmt],
               [ftCostBenchmark].[TotalCostPerUnitAmt]              AS [TotalCostPerUnitAmt],
               [ftCostBenchmark].[TotalUnitQty]                     AS [TotalUnitQty],
               [ftCostBenchmark].[RC]                               AS [RC]
        FROM   [dbo].[ftCostBenchmark] AS [ftCostBenchmark]) AS [Extent1]
ORDER  BY [Extent1].[MonthBeginDt] ASC,
          [Extent1].[dmCostBenchmarkKey] ASC,
          [Extent1].[dmProductKey] ASC,
          [Extent1].[IsImputedFlg] ASC
Run Code Online (Sandbox Code Playgroud)

虽然我没有明确请求任何排序,但是添加了order by子句,其中包括为实体定义的复合实体键中包含的字段.执行此查询会花费大量时间并在数据库上生成页锁.ORDER BY从SQL Server环境中删除查询会在不到一毫秒的时间内返回结果.

所以我的问题是:

如何阻止EF将该order by子句添加到查询中?

Cra*_*ntz 5

没有指定订单,行限制没有任何意义.

如果要按存储顺序检索记录,请创建聚簇索引并在查询中明确指定它.

一种方法是使用查询拦截器.


jer*_*rry 0

如果“order by”子句中列的名称和顺序一致,则用户可能会希望得到此结果。

只需要在表上加一个索引,或者修改主键,这样检索时就可以使用索引了。

create index x on [dbo].[ftCostBenchmark]
                      ([MonthBeginDt],
                       [dmCostBenchmarkKey],
                       [dmProductKey],
                       [IsImputedFlg])
                  include
                       (existing-primarykey-on-the-table)
Run Code Online (Sandbox Code Playgroud)

奇怪的是查询中没有 where 子句。如果您为了简洁而删除了 where 子句,请将这些字段放在索引的前面。