我们可以用 UNION ALL 来交换逻辑或吗?

ada*_*m.g 2 sql-server t-sql union

我看到有人交换了下面的代码:

SELECT
    PK1
    , PK2
    , PK3
    , PK4
    , C
    , B
    , SUM(NUMERIC_1)
    , SUM(NUMERIC_2)
    , MAX(NUMERIC_3)
    , SUM(NUMERIC_4)
FROM MATDOC_EXTRACT
WHERE A = ''
      AND (
          (
              (
              B = ''
              OR B = 'K'
          )
              AND (
                  C = '01'
                  OR C = '02'
                  OR C = '07'
                  OR C = '08'
              )
          )
          OR (
              B = ''
              AND (
                  C = '03'
                  OR C = '04'
              )
          )
      )
GROUP BY PK1
         , PK2
         , PK3
         , PK4
         , C
         , B;

Run Code Online (Sandbox Code Playgroud)

对于这个

SELECT
    PK1
    , PK2
    , PK3
    , PK4
    , C
    , B
    , SUM(NUMERIC_1)
    , SUM(NUMERIC_2)
    , MAX(NUMERIC_3)
    , SUM(NUMERIC_4)
FROM sap.MATDOC_EXTRACT
WHERE A = N''
      AND B = N''
      AND C IN (N'01', N'02', N'07', N'08', N'03', N'04')
GROUP BY PK1
         , PK2
         , PK3
         , PK4
         , C
         , B
UNION ALL
SELECT
    PK1
    , PK2
    , PK3
    , PK4
    , C
    , B
    , SUM(NUMERIC_1)
    , SUM(NUMERIC_2)
    , MAX(NUMERIC_3)
    , SUM(NUMERIC_4)
FROM sap.MATDOC_EXTRACT
WHERE A = N''
      AND B = N'K'
      AND C IN (N'01', N'02', N'07', N'08')
GROUP BY PK1
         , PK2
         , PK3
         , PK4
         , C
         , B;
Run Code Online (Sandbox Code Playgroud)

他们平等吗?

Mar*_*ith 6

一个潜在的重要区别是,在第二种情况下,文字是nvarchar,而在第一种情况下,文字是varchar

然而忽略这一方面......

是的

SELECT *
FROM   TABLE
WHERE  predicate_a
        OR predicate_b 
Run Code Online (Sandbox Code Playgroud)

可以重写为

SELECT *
FROM   TABLE
WHERE  predicate_a
UNION ALL
SELECT *
FROM   TABLE
WHERE  predicate_b 
Run Code Online (Sandbox Code Playgroud)

只要predicate_apredicate_b是互斥的。

predicate_a否则,与两者匹配的行将predicate_b错误地返回两次。

UNION ALL在这种情况下,由于has的两个分支predicate_a包含B = N''并且predicate_b包含B = N'K',则满足此条件。

在您的情况下,您有 10 个不同的等式谓词A, B, C- 因此,如果您有一个索引,其中这些列按某种顺序排列,那么它可能可以通过十个搜索谓词来解决。

A C
'' '' 01
'' '' 02
'' '' 07
'' '' 08
'' K 01
'' K 02
'' K 07
'' K 08
'' '' 03
'' '' 04

当使用 编写的查询没有给出所需的索引查找或具有其他不需要的方面时,重写ORas有时可能是一种有用的技术。UNION ALLOR

如果我尝试

CREATE TABLE T1(A VARCHAR(1), B VARCHAR(1), C VARCHAR(2), INDEX IX (A, B, C))

UPDATE STATISTICS T1 WITH ROWCOUNT = 50000000, PAGECOUNT = 500000
UPDATE STATISTICS T1 IX WITH ROWCOUNT = 50000000, PAGECOUNT = 500000
            
SELECT *
FROM T1
WHERE A = ''
      AND (
          (
              (
              B = ''
              OR B = 'K'
          )
              AND (
                  C = '01'
                  OR C = '02'
                  OR C = '07'
                  OR C = '08'
              )
          )
          OR (
              B = ''
              AND (
                  C = '03'
                  OR C = '04'
              )
          )
      )
Run Code Online (Sandbox Code Playgroud)

然后执行计划看起来像

在此输入图像描述

执行计划本质上将其分解为两个单独的索引查找运算符,并将UNION ALL它们组合在一起

  |--Sort(DISTINCT ORDER BY:([Bmk1000] ASC))
       |--Concatenation
            |--Index Seek(OBJECT:([tempdb].[dbo].[T1].[IX]), SEEK:(
                [tempdb].[dbo].[T1].[A]='' AND [tempdb].[dbo].[T1].[B]='' AND [tempdb].[dbo].[T1].[C]='01' 
                OR [tempdb].[dbo].[T1].[A]='' AND [tempdb].[dbo].[T1].[B]='' AND [tempdb].[dbo].[T1].[C]='02' 
                OR [tempdb].[dbo].[T1].[A]='' AND [tempdb].[dbo].[T1].[B]='' AND [tempdb].[dbo].[T1].[C]='07' 
                OR [tempdb].[dbo].[T1].[A]='' AND [tempdb].[dbo].[T1].[B]='' AND [tempdb].[dbo].[T1].[C]='08' 
                OR [tempdb].[dbo].[T1].[A]='' AND [tempdb].[dbo].[T1].[B]='K' AND [tempdb].[dbo].[T1].[C]='01' 
                OR [tempdb].[dbo].[T1].[A]='' AND [tempdb].[dbo].[T1].[B]='K' AND [tempdb].[dbo].[T1].[C]='02' 
                OR [tempdb].[dbo].[T1].[A]='' AND [tempdb].[dbo].[T1].[B]='K' AND [tempdb].[dbo].[T1].[C]='07' 
                OR [tempdb].[dbo].[T1].[A]='' AND [tempdb].[dbo].[T1].[B]='K' AND [tempdb].[dbo].[T1].[C]='08') ORDERED FORWARD)
            |--Index Seek(OBJECT:([tempdb].[dbo].[T1].[IX]), SEEK:(
               [tempdb].[dbo].[T1].[A]='' AND [tempdb].[dbo].[T1].[B]='' AND [tempdb].[dbo].[T1].[C]='03' 
            OR [tempdb].[dbo].[T1].[A]='' AND [tempdb].[dbo].[T1].[B]='' AND [tempdb].[dbo].[T1].[C]='04') ORDERED FORWARD)
Run Code Online (Sandbox Code Playgroud)

在两个搜索运算符之间,完整的 10 个索引搜索范围被扩展。

由于某种原因,它似乎没有看到它们不重叠,但是有一个删除重复项的步骤。

UNION ALL在这种情况下,重写确实避免了这种情况

SELECT *
FROM T1
WHERE A = ''
      AND B = ''
      AND C IN ('01', '02', '07', '08', '03', '04')
UNION ALL
SELECT *
FROM T1
WHERE A = ''
      AND B = 'K'
      AND C IN ('01', '02', '07', '08')
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述