使用条件UNION优化计划

问题描述 投票:0回答:1

我正在做一个需要级联参数的报告。参数是否使用级联由用户选择。

为了允许级联,我们需要传递 Date 以在运行时(我们正在使用的报表工具的运行时)对其进行过滤。

我做了这个查询,根据级联参数选择数据:

SELECT
    TableA.Value,
    NULL AS Date
FROM Devises
WHERE @cascading = 0

UNION

SELECT DISTINCT
    TableA.Value,
    TableE.Date

FROM TableA
INNER JOIN TableB
    ON TableA.Id = TableB.TableAId
INNER JOIN TableC
    ON TableB.Id = TableC.TableBId
INNER JOIN TableD
    ON TableC.Id = TableD.TableCId
INNER JOIN TableE
    ON TableD.Id = TableE.TableDId
WHERE @cascading = 1;

UNION 的上半部分比下半部分快。这很好而且很明显,但问题是在运行整个查询时。表现对他们俩来说都很糟糕。显然,SQL 没有正确优化计划;如果@cascading <> '1',则根本不执行 UNION 的下半部分!

我尝试使用 IF ELSE 语句:

IF @cascading = '0'
-- upper part
ELSE
-- lower part

它工作得很好,但是我们的报告工具 DevExpress 除了 SELECT 语句之外不允许任何其他内容。

我尝试使用

OPTION (OPTIMIZE FOR (@cascading = '0'))
,但它显然没有什么重要作用。

您有什么想法或建议来告诉 SQL 如何有效地使用此查询吗?或者你有什么有用的东西吗?

sql-server parameters devexpress union sql-execution-plan
1个回答
1
投票

我认为它不需要是一个联盟。如果您仅在其中一个查询中需要 DISTINCT,请保持其本地化并使用 UNION ALL,这不会引入必须管理联合两侧的额外且不必要的排序运算符。

我也不认为第二个查询需要 DISTINCT。由于您只关心两个表中的行,也许:

SELECT
    TableA.Value,
    NULL AS Date
FROM dbo.Devises
WHERE @cascading = 0

UNION ALL

SELECT 
    a.Value,
    e.Date    
FROM dbo.TableA AS a
INNER JOIN dbo.TableE AS e
ON EXISTS
(
   SELECT 1 FROM TableB AS b
     ON b.TableAId = a.Id
     INNER JOIN dbo.TableC AS c
     ON c.TableBId = b.Id
     INNER JOIN dbo.TableD AS d
     ON d.TableCId = c.Id
     WHERE d.Id = e.TableDId
)
WHERE @cascading = 1;

(但是,样本数据和期望的结果,包括任何让您首先包含 DISTINCT 的边缘情况,都将走得更远。)

© www.soinside.com 2019 - 2024. All rights reserved.