将 SQL CTE 优化为一个

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

我有三个 CTE,所有三个都使用相同的源表 table1 和相同的连接条件。 我想将所有三个合并为一个 CTE 以实现性能并有效地获得结果集。

如何在不影响结果集的情况下做到这一点。 它们之间唯一的区别是 WHERE 子句我想合并那个 WHERE 子句,使整个 CTE 成为一个

a AS (
    select
      ta.document, 
      case when users.ename is null
        then ta.recipient 
        else concat(users.ename, '[', ta.recipient, ']') end as email_to 
    from schema1.table1 ta
    left join users on ta.recipient = users.LDAP_id 
    where ta.action like 'X' 
      and ta.recipient not like ' '
      and ta.document in (select document from head)
),

b AS (
    select
      ta.document,
      isnull(
        string_agg (
          case when users.ename is null
            then ta.recipient
            else concat(users.ename,' [', ta.recipient, ']') end,
          '; '
        ),
        ''
      ) as copy_to
    from schema1.table1 ta
    left join users on ta.recipient = users.LDAP_id
    where ta.usr_flag like 'X'
      and ta.document in (select document from head)
    group by
      ta.document
), 


c AS (
    select
      ta.document, 
      isnull(
        case when users.ename is null
          then ta.recipient
          else concat(users.ename, concat(users.ename,' [', ta.recipient, ']') end,
        ""
      ) as reserved_by
    from schema1.table1 ta
    left join users on ta.recipient = users.LDAP_id 
    where ta.reserved like 'X'
      and ta.document in (select document from head)
)

我试图将这些列纳入一个选择,但我知道如何应用过滤器

sql sql-server performance query-optimization common-table-expression
2个回答
0
投票

您提出的重构可能不是获得良好查询效率所必需的。查询规划器在优化复杂查询方面做得非常好。它知道如何使用 CTE 将您的整体查询转换为抽象数据流树,然后优化这些数据流以使用适当的索引。您可以将(非递归)CTE 视为编写嵌套查询的简单语法——这就是查询规划器对待它们的方式。

最好避免重构:你所拥有的已经过测试并且可以工作。

重构查询仍有可能有所帮助。但是还有其他事情你应该先做。

  1. 添加适当的索引。如果您使用 SSMS——Microsoft 的 SQL Server Management Studio——这个提示适合您:在查询窗口中右键单击,然后选择显示实际执行计划,然后运行查询。执行计划显示有时会建议创建一个新索引。

    创建那个索引,然后再次尝试实际执行计划,看看它是否提出了另一个建立在第一个建议之上的建议。通常 SSMS 建议的索引可以解决您的性能问题。如果不是...

  2. 阅读此然后提出一个具体问题,以寻求有关您实际执行计划的帮助。

  3. 该分析可能会引导您重构查询。

综上所述,您可以通过合并两个 CTE 的 SELECT 子句来组合

a
c
b
是聚合(GROUP BY)查询,因此不能与其他查询合并。它的结果集固有地具有不同的行数,因此除非您知道它将如何连接到其他表,否则您无法开始合并它。


0
投票

不清楚你想如何合并这些数据。假设您只想要一个

UNION ALL
,合并
a
c
非常容易,但是
b
更复杂,需要相当复杂的分组结构,并且可能不值得合并。

请注意,一些

case
表达式已被简化。

merged_a_and_b AS (
    select
      ta.document,

      case when ta.action like 'X'
        then isnull(
          users.ename + '[' + ta.recipient + ']',
          ta.recipient
        )
      end as email_to

      case when ta.reserved not like 'X'
        then isnull(
          isnull(
            users.ename + '[' + ta.recipient + ']',
            ta.recipient
          ),
          ""
        )
        end as reserved_by

    from schema1.table1 ta
    left join users on ta.recipient = users.LDAP_id 
    where (
          ta.action like 'X'  and ta.recipient not like ' '
       or ta.reserved like 'X'
      )
      and ta.document in (select document from head)
)

假设你想要更多的联合风格而不是联合,它会简单得多,特别是如果你可以按

ta.document

聚合所有行
merged AS (
    select
      ta.document,

      string_agg(
        case when ta.action like 'X' and ta.recipient not like ' '
          then isnull(
            users.ename + '[' + ta.recipient + ']',
            ta.recipient
          )
          end,
        '; '
      ) as email_to, 

      isnull(
        string_agg (
          case when users.ename is null and ta.usr_flag like 'X'
            then ta.recipient
            else concat(users.ename,' [', ta.recipient, ']') end,
          '; '
        ),
        ''
      ) as copy_to,

      case when ta.reserved like 'X'
        then isnull(
          string_agg(
            isnull(
              users.ename + users.ename + ' [' + ta.recipient + ']',
              ta.recipient
            ),
            ''
          )
        )
        end as reserved_by

    from schema1.table1 ta
    left join users on ta.recipient = users.LDAP_id 
    where ta.reserved like 'X'
    where ta.document in (select document from head)
)
© www.soinside.com 2019 - 2024. All rights reserved.