| |
Merge Replication and the
'Not for Replication' Attribute
This article outlines answers to the question: 'Why is the NOT FOR REPLICATION attribute sometimes recommended on
foreign keys in merge articles?'.
Background
The merge process assigns tables referenced by a FOREIGN KEY constraint (a parent) a smaller article nickname than that of the referencing table (the child table, or the table on which the FOREIGN KEY constraint is defined).
If a table does not participate in such DRI constraints, the merge setup process assigns the article nickname based on the order in which it adds the article to the publication (in ascending order).
After that, the Merge Agent processes INSERTs and UPDATEs in ascending article nickname order (PK first), and processes DELETEs in descending article nickname order (FK first). To understand more details about this mechanism, have a look
here.
Issues
So, how can there be a problem, and why is the NOT FOR REPLICATION attribute sometimes necessary in merge replication?
There are various posibilities, each outlined below:
(1) You might have created the tables without FK at first, then added the tables as merge articles in the order of child first, then parent. This would have led
replication to assign a lower nickname to child and higher to parent. You might have later added the FK via ALTER TABLE, but this has no effect on the order any more because the nicknames would have already been assigned. One easy way of checking whether this is what you are running into is to run
select nickname,* from dbo.sysmergearticles
order by nickname
In other words, to get the proper order you need to have the FKs defined before the articles are added.
(2) Another way this can happen is with circular relationships:

In such a situation there is no definite logical order of article nicknames.
(3) If parent/child nicknames appear to be correct, then another possibility is that rows are processed in the correct order, but the parent fails due to deadlock, timeout, etc. and so the child fails with FK error. If the parent goes through in the retry phase, the child should also eventually go through.
(4) There is also the possibility of multiple batches, with child coming before parent. For interest's sake, to reproduce this behaviour, insert parent and child rows and then make a lot of other updates in your database and after every few changes run "exec sp_MSmakegeneration". By running sp_MSmakegeneration, you are mimicking running a merge. They both have the effect of packaging all pending changes into generations ready to be replicated - future changes go into new generations. Keep doing this until you have about 150 new rows in MSmerge_genhistory. Now update the parent row. This makes the parent row go to a generation that will go in a later batch, while the child stays in a generation that will go in an earlier batch (default generation batch size = 100). Running merge now should repro the problem. This is just a simple reproduction, and
this article
intricately describes the circumstances in which parent and child records can end up in different batches.
Conclusion
In some circumstances the NOT FOR REPLICATION
attribute may be necessary and hopefully if you find PK/FK errors preventing
the merge agent from running you'll be able to better understand why this
setting is required.
BTW, With custom article processing order (@processing_order in sp_addmergearticle) and session level retry functionality, things are massively improved in Yukon.
|
|