8

ITVF でコードをラップするときに、SQL Server がまったく異なる実行計画を採用している理由がわかりません。ITVF 内のコードを単独で実行すると、クエリは 5 秒で実行されます。ITVF として保存すると、20 分間実行され、結果が得られません。コードを再利用するために、これを ITVF に含めることをお勧めします。コードを ITVF として保存すると深刻なパフォーマンスの問題が発生する理由はありますか?

CREATE FUNCTION myfunction
(
    @start_date date, 
    @stop_date date
)
RETURNS TABLE 
AS
RETURN 
(
    with
    ad as (
        select [START_DATE]
              ,[STOP_DATE]
              ,ID
              ,NAME
              ,'domain1\' + lower(DOMAIN1_NAME)
               collate database_default as ad_name
        from EMP_INFO
        where DOMAIN1_NAME != ''
        union
        select [START_DATE]
              ,[STOP_DATE]
              ,ID
              ,NAME
              ,'domain2\' + lower(DOMAIN2_NAME)
               collate database_default as ad_name
        from EMP_INFO
        where DOMAIN2_NAME != ''
    )
    select ad.ID
          ,ad.NAME
          ,COUNT(*) as MONITORS
    from scores
    join users
        on (scores.evaluator_id = users.[user_id])
    join ad
        on (lower(users.auth_login) = ad.ad_name and
            scores.[start_date] between ad.[START_DATE] and ad.[STOP_DATE])
    where scores.[start_date] between @start_date and @stop_date
    group by ad.ID
            ,ad.NAME
)

編集:

わかりました...私は問題を理解したと思います...しかし、私はそれを理解していません. おそらく、まったく新しい質問を投稿する必要があります。あなたの考えを教えてください。ここでの問題は、リテラルを使用して関数を呼び出すと、非常に遅いことです...変数を使用して呼び出すと、高速になります。

-- Executes in about 3 seconds
declare @start_date date = '2012-03-01';
declare @stop_date date = '2012-03-31';
select *
from myfunction(@start_date, @stop_date);

--Takes forever!  Never completes execution...
select *
from myfunction('2012-03-01', '2012-03-31')

何か案は?

4

1 に答える 1

8

リテラルを使用すると、SQL Server は列の統計を調べて返される行数を見積もり、その仮定に基づいて適切な計画を選択できます。変数を使用すると、コンパイル時に値がわからないため、推測に頼ります。

実際の統計を参照するときよりも推測するときに計画が優れている場合、これは統計を更新する必要がある可能性が高いことを示しています。

統計の自動更新をオンにしている場合は、統計、行の見積もり、および昇順の日付列で問題が発生する可能性があります

于 2012-04-06T21:39:57.363 に答える