Обеспечение уникальности нескольких больших полей URL в MS SQL - PullRequest
4 голосов
/ 15 сентября 2011

У меня есть таблица со следующим определением:

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);

Мысли

Ответы [ 2 ]

4 голосов
/ 15 сентября 2011

Я бы сделал вычисляемый столбец с хешем URL-адресов, а затем создал бы уникальный индекс / ограничение для этого.Попробуйте сделать хеш постоянным вычисляемым столбцом.Это не должно быть пересчитано после вставки.

3 голосов
/ 15 сентября 2011

Следуя идеям из разговора в комментариях.Предполагая, что вы можете изменить тип данных URL-адреса на VARCHAR(900) (или NVARCHAR(450), если вы действительно считаете, что вам нужны URL-адреса Unicode) и быть довольным ограничением длины 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.
*/
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...