如何根据传递的参数选择 Union ALL(需要优化)?

Posted

技术标签:

【中文标题】如何根据传递的参数选择 Union ALL(需要优化)?【英文标题】:How can I choose Union ALL according to passed parameter ( need optimization )? 【发布时间】:2010-12-12 05:41:06 【问题描述】:

假设我们有一个存储过程,它采用布尔值 @IsAllowed 参数,如果它通过 True 我应该从两个表中选择数据 A,B (我将在我的情况下使用 Union ALL )否则它通过了False 我应该从一张表中选择数据A ...我用以下方式写它:

Create PROCEDURE TestSP
(
    @IsAllowed bit
)
AS

IF @IsAllowed = 1
BEGIN
    Select ID, Username From A
    Union ALL
    Select ID, Username From B
END
ELSE
    Select ID, Username From A

这是最好的方法吗?虽然在我的真实案例中,SP 在第一个查询的 where 条件中使用了大约 9 个参数,这意味着我将编写第一个查询两次并进行任何更改在其中我必须注意在 2 个不同的地方拥有相同的副本

【问题讨论】:

BA 的子集吗?还是来自一个表的两个不同的结果集? A 是一个在结构上与表 B 不同的表,但它具有我想要返回的相交列...我使用 sql server 2005 相交列?但是你没有加入他们;您将它们附加到结果集中。 【参考方案1】:

试试这个。

SELECT *
FROM   A
UNION ALL
SELECT *
FROM  B
WHERE @isAllowed = 1

【讨论】:

这是否会影响性能,因为它将迭代 B 表中的所有行.. ? 让我快速检查一下。我运行一下看看执行计划。 它似乎正在对查询中的第二个表进行聚集索引扫描。它(在我的简单测试中)约占执行成本的 45-50%。我会在您的特定场景中尝试它,看看它是否在所需的参数范围内。即使我返回了数千条记录,我的所有查询也会在一两秒内返回。【参考方案2】:

我对这个查询并不是很着迷,但如果你想完全避免二次选择的成本,我认为你必须用它来换取一个临时表。

IF OBJECT_ID('tempdb..#tableA') IS NOT NULL 
    DROP TABLE #tableA

SELECT  ID,Username
INTO    #tableA
FROM    tableA

IF @isAllowed = 1 
    BEGIN
        SELECT  ID,Username
        FROM    #tableA
        UNION ALL
        SELECT  ID,Username
        FROM    B
    END
ELSE 
    BEGIN
        SELECT  ID,Username
        FROM    #tableA
    END

DROP TABLE  #tableA

如果您的记录集足够小以至于您不介意将其放入内存中(而不是将其写入磁盘,I/O 就是其中之一),请随意将 # 表更改为 @ 表的主要瓶颈)。请记住,您必须实际声明表(带有列定义),而不是 SELECTing INTO

【讨论】:

以上是关于如何根据传递的参数选择 Union ALL(需要优化)?的主要内容,如果未能解决你的问题,请参考以下文章

UNION ALL 参数化查询

带有 union all 的存储过程循环

union all 效率问题

有比 UNION ALL 更简单的方法吗?

如何在 Access 中对表的所有列进行 UNION ALL

union 与 union all 的表现