连接多个nvarchar列

cs0*_*815 3 t-sql sql-server

我有这样一张桌子:

CREATE TABLE [dbo].[Table](
    [Id] [INT] IDENTITY(1,1) NOT NULL,
    [A] [NVARCHAR](150) NULL,
    [B] [NVARCHAR](150) NULL,
    [C] [NVARCHAR](150) NULL,
    [D] [NVARCHAR](150) NULL,
    [E] [NVARCHAR](150) NULL,
 CONSTRAINT [con] PRIMARY KEY CLUSTERED 
(
    [Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO
Run Code Online (Sandbox Code Playgroud)

并寻找性能改进以加入此表.

选项1 - 将所有字符串组合成nvarchar主键,然后执行:

Source.[A] + Source.[B] + Source.[C] + Source.[D] + Source.[E] = Table.PKString
Run Code Online (Sandbox Code Playgroud)

据我所知,这是不好的做法.

选项2 - 使用:

Source.[A] + Source.[B] + Source.[C] + Source.[D] + Source.[E] = Target.[A] + Target.[B] + Target.[C] + Target.[D] + Target.[E]
Run Code Online (Sandbox Code Playgroud)

选项3 - 使用:

Source.[A] = Target.[A] And
...
Source.[E] = Target.[E]
Run Code Online (Sandbox Code Playgroud)

Mar*_*ith 5

您的选项1将无法正常工作,因为它将('ab','c')视为等于('a','bc').

您的列也可以为空,并且连接null会产生null.

nvarchar由于可空性,您无法将所有列组合成主键,即使没有这样,您仍然有失败的风险,因为最大长度将是1,500字节,远远超过最大索引键列大小.

由于类似的长度原因,使用所有列的复合索引也不起作用.

您可以创建一个计算列,该列使用所有这5列值作为输入来计算校验和或散列值和索引.

ALTER TABLE [dbo].[Table]
  ADD HashValue AS CAST(hashbytes('SHA1', ISNULL([A], '') + ISNULL([B], '')+ ISNULL([C], '')+ ISNULL([D], '')+ ISNULL([E], '')) AS VARBINARY(20));


CREATE INDEX ix
  ON [dbo].[Table](HashValue)
  INCLUDE ([A], [B], [C], [D], [E]) 
Run Code Online (Sandbox Code Playgroud)

然后在哈希冲突的情况下,在其他5列的剩余谓词的连接中使用它.

如果你想NULL比较平等,你可以使用

SELECT *
FROM   [dbo].[Table1] source
       JOIN [dbo].[Table2] target
         ON source.HashValue = target.HashValue
            AND EXISTS(SELECT source.A,
                              source.B,
                              source.C,
                              source.D,
                              source.E
                       INTERSECT
                       SELECT target.A,
                              target.B,
                              target.C,
                              target.D,
                              target.E) 
Run Code Online (Sandbox Code Playgroud)

请注意,上面创建的索引基本上会重现整个表,因此如果您的查询需要覆盖,您可能需要考虑创建为集群.