如何强制查询优化器更有效地处理我的查询?

时间:2013-12-13 16:21:01

标签: sql-server

我有一个报告调度系统,其中每个报告都有一组参数,动态提示用户,然后报告作为SQL代理作业执行,将输出保存到存档数据库以供日后查看。

这一切都运行良好,但用户想要更改其中一个参数。他们曾经指定一个成员和位置(这定义了一个客户),但现在他们希望能够指定多个成员和位置。例如,根据他们在英国和NI(两个地点)的运营情况,他们可能希望看到2012年Comet销量排名前50位的产品。

我的报告过去需要几秒钟才能运行,但是这次更改现在需要大约8分钟!

当报告调度程序获取报告请求时,它会将成员/位置列表存储在表中,然后将其链接到报告中。这似乎是事情出错的地方。

以下是报告的开头(这足以解决性能问题):

CREATE FUNCTION [Report].[GetTopSaleQuantityPackagingTonnage] (
    @ReportHandle UNIQUEIDENTIFIER,
    @DSFYear INT,
    @DateFrom DATETIME,
    @DateTo DATETIME,   
    @LevelId INT,
    @MaterialId INT, --Base Material
    @TopN INT,
    @TopNType VARCHAR(50),
    @WeightSource VARCHAR(50),
    @ImportExportFlag VARCHAR(1) = NULL)
RETURNS TABLE
AS
    RETURN
    WITH MemberList AS (
        SELECT 
            MemberId, 
            LocationId 
        FROM 
            Report.ReportMemberLocation 
        WHERE 
            ReportHandle = @ReportHandle),
    ProductList AS (
        SELECT DISTINCT
            pw.ProductId,
            pw.WeightSource,
            m.MaterialId
        FROM
            PackagingWeightDerivedBase pw
            INNER JOIN Material m ON m.ExtendedMaterialId = pw.ExtendedMaterialId
        WHERE
            EXISTS (SELECT * FROM MemberList ml WHERE ml.MemberId = pw.MemberId)
            AND ISNULL(@LevelId, pw.LevelId) = pw.LevelId
            AND ISNULL(@MaterialId, m.MaterialId) = m.MaterialId)
SELECT * FROM ProductList;

如果我将单个过滤器添加到ProductList CTE,例如

AND MemberId = 163
然后它又回到了几秒而不是几分钟。 MemberId = 163是我运行报告的成员,在这种情况下,他们只有一个位置。

我最初尝试过这个:

    ProductList AS (
        SELECT DISTINCT
            pw.ProductId,
            pw.WeightSource,
            m.MaterialId
        FROM
            MemberList ml
            INNER JOIN PackagingWeightDerivedBase pw ON pw.MemberId = ml.MemberId
            INNER JOIN Material m ON m.ExtendedMaterialId = pw.ExtendedMaterialId
        WHERE
            ISNULL(@LevelId, pw.LevelId) = pw.LevelId
            AND ISNULL(@MaterialId, m.MaterialId) = m.MaterialId)

......但那更慢,我离开了30分钟,它从未完成。此外,这在任何情况下都不是严格正确的,因为它会为成员/位置过滤器中的每一行带回重复的结果。

所以我知道问题在于优化器没有明智地处理这个问题。基本上它有:

Report.ReportMemberLocation - 1 row
Material - about 50 rows
PackagingWeightDerivedBase - millions of rows

...当它发现它们属于不同的成员时,它必须拔出数百万行数据,以便将99.99%的数据扔掉。

我是否可以通过其他方式表达此查询以强制优化器首先按成员列表过滤权重表?或者也许是一些我不知道的提示?

0 个答案:

没有答案