Manage and Monitor Identity Ranges in SQL Server Transactional Replication
- by Yaniv Etrogi
Problem
When using transactional
replication to replicate data in a one way topology from a publisher to a
read-only subscriber(s) there is no need to manage identity ranges. However, when
using transactional replication to replicate data in a two way replication topology
-
between two or more servers there is a need to manage identity ranges in order
to prevent a situation where an INSERT commands fails on a PRIMARY KEY violation
error due to the replicated row being inserted having a value for the
identity column which already exists at the destination database.
Solution
There are two
ways to address this situation:
Assign a range of identity values
per each server.
Work with parallel identity values.
The first
method requires some maintenance while the second method does not and so the
scripts provided with this article are very useful for anyone using the
first method. I will explore this in more detail later in the article.
In the first
solution set server1 to work in the range of 1 to 1,000,000,000 and server2
to work in the range of 1,000,000,001 to 2,000,000,000. The ranges are set and defined using the DBCC
CHECKIDENT command and when the ranges in this example are well maintained you
meet the goal of preventing the INSERT commands to fall due to a PRIMARY KEY
violation. The first insert at server1 will get the identity value of 1, the second insert will get the value of 2 and so on while
on server2 the first insert will get the identity value of 1000000001, the
second insert 1000000002 and so on thus avoiding a conflict.
Be aware that when a row is inserted the identity value (seed) is generated as part of the insert command at each server and the inserted row is replicated. The replicated row includes the identity column’s value so the data remains consistent across all servers but you will be able to tell on what server the original insert took place due the range that the identity value belongs to.
In the second
solution you do not manage ranges but enforce a situation in which identity
values can never get overlapped by setting the first identity value (seed) and
the increment property one time only during the CREATE TABLE command of each
table.
So a table on
server1 looks like this:
CREATE TABLE T1 ( c1 int NOT NULL IDENTITY(1, 5) PRIMARY KEY CLUSTERED ,c2 int NOT NULL );
And a table
on server2 looks like this:
CREATE TABLE T1( c1 int NOT NULL IDENTITY(2, 5) PRIMARY KEY CLUSTERED ,c2 int NOT NULL );
When these two
tables are inserted the results of the identity values look like this:
Server1: 1, 6, 11, 16, 21, 26…
Server2: 2, 7, 12, 17, 22, 27…
This assures
no identity values conflicts while leaving a room for 3 additional servers to participate
in this same environment. You can go up to 9 servers using this method by
setting an increment value of 9 instead of 5 as I used in this example.
Continues…