0

テーブル(約18000レコードのリソース)とこの本体のテーブル値関数があります:

ALTER FUNCTION [dbo].[tfn_GetPackageResources]
(   
    @packageId int=null,
    @resourceTypeId int=null,
    @resourceCategoryId int=null,
    @resourceGroupId int=null,
    @resourceSubGroupId int=null
)
RETURNS TABLE 
AS
RETURN 
(

    SELECT Resources.*
    FROM    Resources 
            INNER JOIN ResourceSubGroups ON Resources.ResourceSubGroupId=ResourceSubGroups.Id
            INNER JOIN ResourceGroups ON ResourceSubGroups.ResourceGroupId=ResourceGroups.Id
            INNER JOIN ResourceCategories ON ResourceGroups.ResourceCategoryId=ResourceCategories.Id
            INNER JOIN ResourceTypes ON ResourceCategories.ResourceTypeId=ResourceTypes.Id
    WHERE
        (@resourceSubGroupId IS NULL OR ResourceSubGroupId=@resourceSubGroupId) AND
        (@resourceGroupId IS NULL OR ResourceGroupId=@resourceGroupId) AND
        (@resourceCategoryId IS NULL OR ResourceCategoryId=@resourceCategoryId) AND
        (@resourceTypeId IS NULL OR ResourceTypeId=@resourceTypeId) AND
        (@packageId IS NULL OR PackageId=@packageId) 



)

今、私はこのようなクエリを作成します:

SELECT  id
FROM    dbo.tfn_GetPackageResources(@sourcePackageId,null,null,null,null)
WHERE   id not in(  
    SELECT  a.Id 
    FROM    dbo.tfn_GetPackageResources(@sourcePackageId,null,null,null,null) a INNER JOIN
            dbo.tfn_GetPackageResources(@comparePackageId,null,null,null,null) b
            ON  a.No = b.No AND 
                a.UnitCode=b.UnitCode AND 
                a.IsCompound=b.IsCompound AND 
                a.Title=b.Title
    )

このクエリには約10秒かかります!(各部分のクエリは非常に高速に実行されますが、全体に時間がかかります)確認しましLEFT JOINNOT EXISTSが、結果は同じでした。しかし、Resourcesテーブルで直接クエリを実行すると、1秒以内で完了します。高速クエリは次のとおりです。

select * from resources where id not in (select id from resources)

どうすれば解決できますか?

4

3 に答える 3

2

UDFはマクロのように展開されます。

したがって、完全なクエリには

  • IN句の9つの内部結合
  • メインSELECTの4つの内部結合。
  • (... IS NULL OR ...)WHERE句ごとに合計15回適用します。

この拡張のために、巧妙なコードの再利用のアイデアは失敗し
ます。SQLは通常、この再利用には役立ちません。

単純にする:

SELECT
    R.id
FROM
    Resources R
WHERE
    R.PackageId = @sourcePackageId
    AND 
    R.id not in (  
        SELECT  a.Id 
       FROM    Resources  a
               INNER JOIN
               Resources  b
                   ON  a.No = b.No AND 
                        a.UnitCode=b.UnitCode AND 
                        a.IsCompound=b.IsCompound AND 
                        a.Title=b.Title
        WHERE
             a.PackageId = @sourcePackageId
             AND
             b.PackageId = @comparePackageId
    )

詳細については、ここで私の他の回答を参照してください:

于 2013-02-20T08:24:41.003 に答える
0

関数で、返すテーブルのタイプを宣言し、主キーを含めます。このようにして、IDフィルターはIDをより効率的に検索できるようになります。

構文については、http://msdn.microsoft.com/en-us/library/ms191165 (v = sql.105).aspxを参照してください。

于 2013-02-20T08:22:42.760 に答える
0

試してみるべきことは、1 つの複雑なクエリを、結果を一時テーブルに格納する複数の単純なクエリに分割することです。このようにして、1 つの複雑な実行プランが、複雑な実行の実行時間よりも短い合計実行時間の複数の単純なプランに置き換えられます。予定:

SELECT  *
INTO    #temp1
FROM    dbo.tfn_GetPackageResources(@sourcePackageId,null,null,null,null)

SELECT  *
INTO    #temp2
FROM    dbo.tfn_GetPackageResources(@comparePackageId,null,null,null,null)

SELECT  a.Id 
INTO    #ids
FROM    #temp1 a 
INNER JOIN
        #temp2 b ON  
        a.No = b.No 
AND     a.UnitCode=b.UnitCode 
AND     a.IsCompound=b.IsCompound 
AND     a.Title=b.Title

SELECT  id
FROM    #temp1
WHERE   id not in(  
    SELECT  Id 
    FROM    #ids
)

-- you can also try replacing the above query with this one if it performs faster
SELECT  id
FROM    #temp1 t
WHERE   NOT EXISTS 
(
    SELECT Id FROM #ids i WHERE i.Id = t.id
)
于 2013-02-20T08:24:55.183 に答える