根据CREATE INDEX
文档:
单个组合索引键最多可以组合16列。
我们有一个约18列的表格,需要形成一个唯一的组合。该表对性能不敏感-我们很少更新值/插入记录。我们只需要确保避免重复记录即可...并认为我们可以施加一个简单的唯一性约束。
有任何想法吗?如果有更好的方法,我愿意完全避免使用唯一的索引/约束。
根据CREATE INDEX
文档:
单个组合索引键最多可以组合16列。
我们有一个约18列的表格,需要形成一个唯一的组合。该表对性能不敏感-我们很少更新值/插入记录。我们只需要确保避免重复记录即可...并认为我们可以施加一个简单的唯一性约束。
有任何想法吗?如果有更好的方法,我愿意完全避免使用唯一的索引/约束。
Answers:
添加一个包含18个键的持久计算列,然后在计算列上创建唯一索引:
alter table t add all_keys as c1+c2+c3+...+c18 persisted;
create unique index i18 on t (all_keys);
另一种方法是创建索引视图:
create view v
with schemabinding
as select c1+c2+c3+...+c18 as all_keys
from dbo.t;
create unique clustered index c18 on v(all_keys);
请参阅创建索引视图。
两种方法都允许部分键聚合:将c1 + c2 + c3聚合为k1,将c4 + c5 + c6聚合为k2等,然后在(k1,k2,...)上索引/创建索引视图。Thia对于范围扫描可能是有益的(索引可用于在c1 + c2 + c3上进行搜索。
当然,+
在我的示例中,所有操作都是字符串聚合,实际使用的运算符取决于所有这些列的类型(即,您可能必须使用显式强制转换)。
PS。由于唯一性约束是由唯一性索引强制执行的,因此对唯一性索引的任何限制也将适用于唯一性约束:
create table t (
c1 char(3), c2 char(3), c3 char(3), c4 char(3),
c5 char(3), c6 char(3), c7 char(3), c8 char(3),
c9 char(3), c10 char(3), c11 char(3), c12 char(3),
c13 char(3), c14 char(3), c15 char(3), c16 char(3),
c17 char(3), c18 char(3), c19 char(3), c20 char(3),
constraint unq unique
(c1,c2,c3,c4,c5,c6,c7,c8,c9,c10,c11,c12,c13,c14,c15,c16,c17,c18));
go
Msg 1904, Level 16, State 1, Line 3
The index '' on table 't' has 18 column names in index key list.
The maximum limit for index or statistics key column list is 16.
Msg 1750, Level 16, State 0, Line 3
Could not create constraint. See previous errors.
但是,在持久化的计算列上创建约束的工作原理是:
create table t (
c1 char(3), c2 char(3), c3 char(3), c4 char(3),
c5 char(3), c6 char(3), c7 char(3), c8 char(3),
c9 char(3), c10 char(3), c11 char(3), c12 char(3),
c13 char(3), c14 char(3), c15 char(3), c16 char(3),
c17 char(3), c18 char(3), c19 char(3), c20 char(3),
all_c as
c1+c2+c3+c4+c5+c6+c7+c8+c9+c10+c11+
c12+c13+c14+c15+c16+c17+c18
persisted
constraint unq unique (all_c));
go
显然,持久化列会占用磁盘上的空间,因此该方法可能对非常大的表不利。索引视图方法不存在此问题,它仅消耗索引空间,而不消耗计算列和索引的空间。
我认为您最好将唯一索引检查放在使用HASHBYTES('MD5', ...)
18列组合生成的计算列上。
我遇到了这个问题,我的高级DBA建议使用唯一性检查功能。我的插入内容相对较小且很少出现(每个月初插入约1000行),我唯一关心的是强制执行唯一性。
CREATE FUNCTION dbo.fn_UQ_table1 ()
RETURNS BIT
AS
BEGIN
DECLARE @ResultBit BIT = 1
IF EXISTS(
SELECT COUNT(*)
FROM [table1]
GROUP BY [c1],[c2],[c3],[c4],[c5],[c6],
[c7],[c8],[c9],[c10],[c11],[c12],
[c13],[c14],[c15],[c16]
HAVING COUNT(*) > 1)
SELECT @ResultBit = 0
RETURN @ResultBit
END
SELECT dbo.fn_UQ_table1()
ALTER TABLE [table1]
WITH NOCHECK ADD
CONSTRAINT [CK_UQ] CHECK (([dbo].[fn_UQ_table1]()=1))
@RBarryYoung,我现在还没有评论要发表,但是我对HASHBYTES解决方案遇到了麻烦,因为我的一种数据类型是日期时间,而且我犯了newbie(?)错误,没有为我的用户提供可选的style参数。转换为varchar时的CONVERT函数。如果没有样式,则尝试添加PERSISTED UNIQUE NONCLUSTERED
约束时会出现以下错误:
"column 'key_hash' in table 'table1' cannot be persisted because
the column is non-deterministic."
您可以合并一些值,以创建一个新的唯一值,并存储该值和当前数据。
创建一个用户定义的函数来创建新值,并创建一个触发器,以在添加数据时填充该字段,这样您就不必在维护该字段上有太多开销。
将您的两个或三个字段组合在一起将使您的访问量限制在16个以下。