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 表上运行查询,只需要一秒钟或更短的时间!快速查询是:

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

我该如何解决?

4

3 回答 3

2

您的 UDF 像宏一样扩展。

所以你的完整查询有

  • IN 子句中的 9 个 INNER JOIN
  • 主 SELECT 中的 4 个 INNER JOIN。
  • 您对每个 WHERE 子句总共应用(... IS NULL OR ...)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

您应该尝试将一个复杂的查询分解为多个简单的查询,并将其结果存储在临时表中,这样一个复杂的执行计划将被几个简单的计划取代,这些计划的总执行时间可能比复杂执行的执行时间更短计划:

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 回答
0

在您的函数中,声明它返回的表的类型,并包含一个主键。这样,ID 过滤器将能够更有效地查找 ID。

有关语法,请参阅http://msdn.microsoft.com/en-us/library/ms191165(v=sql.105).aspx

于 2013-02-20T08:22:42.760 回答