Indexing 确保MS SQL中多个大URL字段的唯一性
我有一个具有以下定义的表:Indexing 确保MS SQL中多个大URL字段的唯一性,indexing,unique-constraint,sql-server,Indexing,Unique Constraint,Sql Server,我有一个具有以下定义的表: CREATE TABLE url_tracker ( id int not null identity(1, 1), active bit not null, install_date int not null, partner_url nvarchar(512) not null, local_url nvarchar(512) not null, public_url nvarchar(512) not null,
CREATE TABLE url_tracker (
id int not null identity(1, 1),
active bit not null,
install_date int not null,
partner_url nvarchar(512) not null,
local_url nvarchar(512) not null,
public_url nvarchar(512) not null,
primary key(id)
);
我有一个要求,这三个URL总是唯一的-任何单独的URL可以出现很多次,但三者的组合必须是唯一的(对于给定的一天)
起初我认为我可以做到这一点:
CREATE UNIQUE INDEX uniques ON url_tracker
(install_date, partner_url, local_url, public_url);
然而,这给了我一个警告:
Warning! The maximum key length is 900 bytes. The index 'uniques' has maximum
length of 3076 bytes. For some combination of large values, the insert/update
operation will fail.
我了解了INCLUDE
参数到CREATE INDEX
,但是根据将命令转换为使用INCLUDE
不会强制URL的唯一性
CREATE UNIQUE INDEX uniques ON url_tracker (install_date)
INCLUDE (partner_url, local_url, public_url);
如何在几个相对较大的nvarchar字段上强制唯一性
决议 因此,从评论、回答和更多研究中,我得出结论,我可以做到:
CREATE TABLE url_tracker (
id int not null identity(1, 1),
active bit not null,
install_date int not null,
partner_url nvarchar(512) not null,
local_url nvarchar(512) not null,
public_url nvarchar(512) not null,
uniquehash AS HashBytes('SHA1',partner_url+local_url+public_url) PERSISTED,
primary key(id)
);
CREATE UNIQUE INDEX uniques ON url_tracker (install_date,uniquehash);
想法?我会用URL的名称创建一个计算列,然后在此列上创建一个唯一的索引/约束。考虑将哈希变成一个持久化的计算列。插入后不必重新计算。遵循评论中对话的想法。假设您可以将URL的数据类型更改为
VARCHAR(900)
(或者NVARCHAR(450)
,如果您真的认为您需要Unicode URL),并且对URL的长度限制感到满意,那么此解决方案可以工作。这也假定SQL Server 2008或更高版本。请始终指定您使用的版本;还不够具体,因为解决方案可能因版本而异
设置:
USE tempdb;
GO
CREATE TABLE dbo.urls
(
id INT IDENTITY(1,1) PRIMARY KEY,
url VARCHAR(900) NOT NULL UNIQUE
);
CREATE TABLE dbo.url_tracker
(
id INT IDENTITY(1,1) PRIMARY KEY,
active BIT NOT NULL DEFAULT 1,
install_date DATE NOT NULL DEFAULT CURRENT_TIMESTAMP,
partner_url_id INT NOT NULL REFERENCES dbo.urls(id),
local_url_id INT NOT NULL REFERENCES dbo.urls(id),
public_url_id INT NOT NULL REFERENCES dbo.urls(id),
CONSTRAINT unique_urls UNIQUE
(
install_date,partner_url_id, local_url_id, public_url_id
)
);
插入一些URL:
INSERT dbo.urls(url) VALUES
('http://msn.com/'),
('http://aol.com/'),
('http://yahoo.com/'),
('http://google.com/'),
('http://gmail.com/'),
('http://stackoverflow.com/');
现在让我们插入一些数据:
-- succeeds:
INSERT dbo.url_tracker(partner_url_id, local_url_id, public_url_id)
VALUES (1,2,3), (2,3,4), (3,4,5), (4,5,6);
-- fails:
INSERT dbo.url_tracker(partner_url_id, local_url_id, public_url_id)
VALUES(1,2,3);
GO
/*
Msg 2627, Level 14, State 1, Line 3
Violation of UNIQUE KEY constraint 'unique_urls'. Cannot insert duplicate key
in object 'dbo.url_tracker'. The duplicate key value is (2011-09-15, 1, 2, 3).
The statement has been terminated.
*/
-- succeeds, since it's for a different day:
INSERT dbo.url_tracker(install_date, partner_url_id, local_url_id, public_url_id)
VALUES('2011-09-01',1,2,3);
清理:
DROP TABLE dbo.url_tracker, dbo.urls;
现在,如果900字节不够,您可以稍微更改URL表:
CREATE TABLE dbo.urls
(
id INT IDENTITY(1,1) PRIMARY KEY,
url VARCHAR(2048) NOT NULL,
url_hash AS CONVERT(VARBINARY(32), HASHBYTES('SHA1', url)) PERSISTED,
CONSTRAINT unique_url UNIQUE(url_hash)
);
其余的不必改变。如果你尝试插入相同的URL两次,你会得到类似的违规行为,例如
INSERT dbo.urls(url) SELECT 'http://www.google.com/';
GO
INSERT dbo.urls(url) SELECT 'http://www.google.com/';
GO
/*
Msg 2627, Level 14, State 1, Line 1
Violation of UNIQUE KEY constraint 'unique_url'. Cannot insert duplicate key
in object 'dbo.urls'. The duplicate key value is
(0xd111175e022c19f447895ad6b72ff259552d1b38).
The statement has been terminated.
*/
您可能需要为每一个获取一个哈希值并比较哈希值。但这会对性能产生负面影响。@JNK我喜欢你的建议,你应该将其作为answer@JNK我也喜欢。不过,您可以将散列存储为持久化的计算列,以减少影响。可能的解决办法是降低租金。这是什么版本的SQL Server?您也可以将URL存储在单独的表中。给他们一个代理
id
,只需为idsp的组合编制索引,一个INCLUDE
列只需“随便便”就可以帮助防止不必要的查找-这就是为什么不能使用它来强制唯一性;它不是键的一部分。@dimo414我认为您可能需要将HASHBYTES强制转换为VARBINARY(20)-此外,如果您认为有任何方法可以使用三个不同的URL生成相同的长字符串,您可能需要在连接过程中以某种方式对其进行唯一分隔-即ab123不明确,可能来自a、b、123或ab、1、23或a、b1,23等等。考虑到每一个都以http://开头,我不认为这是可能的,但如果你认为这很关键,我可以用|来界定它们。