我正在做一个需要级联参数的报告。参数是否使用级联由用户选择。
为了允许级联,我们需要传递 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 如何有效地使用此查询吗?或者你有什么有用的东西吗?
我认为它不需要是一个联盟。如果您仅在其中一个查询中需要 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 的边缘情况,都将走得更远。)