EF和表值函数性能

时间:2012-10-01 07:20:29

标签: c# sql-server entity-framework

我们正在使用Entity Framework 5.0.0,数据库第一种方法。

我已经向我的EDMX导入了几个内联表值函数(ITVF),它返回了IQueryable。返回后,我们经常对它们进行某种类型的操作,如.Skip()。Take()

性能良好,至少几个小时。没有做任何事情(至少我所知道的),性能会在一夜之间降低。

首先,查询将花费大约500毫秒来执行。在整个晚上,性能降低到查询返回超时异常(30-60秒)的水平。这仅在从代码执行表函数时发生,例如:

IQueryable<MyResult> results =
            _context.MyTableFunction("searchforthis")
                .Skip(currentPagingPosition*20).Take(20);

(这不仅仅是我们第一次运行查询时发生这种情况)

但是,如果我们从SQL Server Management Studio直接运行相同的表函数,则查询将在~500ms内执行。

如果我“重新保存”表格功能如下:

ALTER FUNCTION [dbo].[MyTableFunction]......

没有做任何“真正的”更改,即使从代码调用,它也会立即恢复为500毫秒。

我错过了一些明显的想法吗?

1 个答案:

答案 0 :(得分:0)

所以我尝试将Option Recompile添加到内联TVF,但似乎不允许。我发现这一点的唯一方法是创建一个多语句函数,但它们有它们的缺点:

<强>设置

CREATE Table MyTest
(
    ID INT PRIMARY KEY Identity,
    SomeValue VARCHAR(MAX),
    UpdateDate Date
)
CREATE INDEX IDX_MyTest_UpdateDate
 ON MyTest(UpdateDate)


GO

创建功能

 CREATE FUNCTION MyFunction(@FromDate date, @ToDate Date)
 RETURNS TABLE 
 AS
RETURN
(   
    SELECT SomeValue, UpdateDate
    FROM MyTest
    WHERE   UpdateDate >= @FromDate AND
            UpdateDate <=@ToDate
    -- OPTION (RECOMPILE) **** NOT ALLOWED HERE**
)
GO

CREATE FUNCTION MyFunction2(@FromDate date, @ToDate Date)
 RETURNS @retMyFunction TABLE
    (
        SomeValkue VARCHAR(MAX),
        UpdateDate Date
    ) 
 AS
BEGIN
    INSERT INTO @retMyFunction
    SELECT SomeValue, UpdateDate
    FROM MyTest
    WHERE   UpdateDate >= @FromDate AND
            UpdateDate <=@ToDate
    OPTION (RECOMPILE);

    RETURN;
END
GO

加载数据

 INSERT INTO MyTest (SomeValue, UpdateDate)
 SELECT CAST(X.n * Y.n * z.n AS VARCHAR(Max)), DATEADD(D, ROW_NUMBER() OVER (ORDER BY X.n), '2010-01-01')
 FROM (VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10)) X(n)
 CROSS APPLY (VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10)) Y(n)
 CROSS APPLY (VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10)) Z(n)

<强>测试

-- Index Scan
SELECT * FROM MyTest
 WHERE UpdateDate > '2010-01-02' AND UpdateDate < '2020-01-01'
-- Index Seek
 SELECT * FROM MyTest
 WHERE UpdateDate > '2010-01-02' AND UpdateDate < '2010-01-05'


-- Index Scan
SELECT *
FROM MyFunction('2010-01-02', '2020-01-01')
-- Index Scan
SELECT *
FROM MyFunction('2010-01-02', '2010-01-05')


-- Index Scan
SELECT *
FROM MyFunction2('2010-01-02', '2020-01-01')
-- Index Seek
SELECT *
FROM MyFunction2('2010-01-02', '2010-01-05')