Modalità di rilevamento e risoluzione dei conflitti da parte della replica di tipo merge

La replica di tipo merge consente modifiche autonome ai dati in nodi diversi: di conseguenza, si verificano situazioni in cui la modifica apportata in un nodo può essere in conflitto con la modifica apportata agli stessi dati in un altro nodo. In altre situazioni, l'agente di merge rileva un errore quale una violazione di vincolo e non può propagare a un altro nodo la modifica eseguita in uno specifico nodo. In questo argomento vengono descritti i tipi di conflitti, le modalità di rilevamento e risoluzione dei conflitti e i fattori che influiscono sul rilevamento e sulla risoluzione.

Rilevamento e risoluzione di conflitti

L'agente di merge rileva i conflitti utilizzando la colonna lineage della tabella di sistema MSmerge_contents. Se per un articolo è attivato il rilevamento a livello di colonna, viene inoltre utilizzata la colonna COLV1. Queste colonne contengono metadati indicanti il momento dell'inserimento o dell'aggiornamento di una riga o di una colonna e i nodi di una topologia di replica di tipo merge che hanno apportato modifiche alla riga o alla colonna. Per visualizzare questi metadati, è possibile utilizzare la stored procedure di sistema sp_showrowreplicainfo (Transact-SQL).

Nel corso dell'enumerazione delle modifiche da applicare durante la sincronizzazione, l'agente di merge confronta i metadati di ogni riga del server di pubblicazione e del Sottoscrittore. L'agente di merge utilizza questi metadati per stabilire se una riga o una colonna sono state modificate in più di un nodo della topologia, cosa indicante un potenziale conflitto. Dopo il rilevamento di un conflitto, l'agente di merge avvia il sistema di risoluzione dei conflitti specificato per l'articolo che presenta il conflitto e lo utilizza per determinare la riga che prevale nel conflitto. Questa viene applicata nel server di pubblicazione e nel Sottoscrittore, mentre i dati della riga che perde vengono scritti in una tabella dei conflitti.

I conflitti vengono risolti automaticamente e immediatamente dall'agente di merge, a meno che per l'articolo non sia stata scelta la risoluzione dei conflitti interattiva. Per ulteriori informazioni, vedere Risoluzione dei conflitti interattiva. Se si modifica manualmente la riga che prevale in un conflitto utilizzando il visualizzatore conflitti di replica di tipo merge, nel corso della successiva sincronizzazione l'agente di merge applica al server perdente la versione della riga che ha prevalso.

Registrazione dei conflitti risolti

Dopo che l'agente di merge ha risolto il conflitto in base alla logica del sistema di risoluzione dei conflitti, ne registra i dati a seconda del tipo:

  • Per i conflitti di aggiornamento e di inserimento, scrive la versione perdente della riga nella tabella dei conflitti dell'articolo, denominata con il formato conflict_<PublicationName>_<ArticleName>. Le informazioni generali sul conflitto, ad esempio il tipo di conflitto, vengono scritte nella tabella MSmerge_conflicts_info.

  • Per i conflitti di eliminazione, la versione perdente della riga viene scritta nella tabella MSmerge_conflicts_info. Quando un aggiornamento prevale su un'eliminazione, la riga che nel conflitto è risultata perdente non contiene informazioni, poiché è stata eliminata, e in conflict_<PublicationName>_<ArticleName> non viene scritto nulla.

Le tabelle dei conflitti di ogni articolo vengono create nel database di pubblicazione, nel database di sottoscrizione o in entrambi (impostazione predefinita) a seconda del valore specificato per il parametro @conflict_logging di sp_addmergepublication. Ogni tabella dei conflitti ha la stessa struttura dell'articolo su cui è basata, con l'aggiunta della colonna origin_datasource_id. L'agente di merge elimina i dati dalla tabella dei conflitti se sono più vecchi del periodo di memorizzazione dei conflitti della pubblicazione, specificato utilizzando il parametro @conflict_retention di sp_addmergepublication (l'impostazione predefinita è 14 giorni).

Per la visualizzazione dei dati dei conflitti, la replica offre il Visualizzatore conflitti di replica e le stored procedure (sp_helpmergearticleconflicts, sp_helpmergeconflictrows e sp_helpmergedeleteconflictrows). Per ulteriori informazioni, vedere Procedura: Visualizzazione e risoluzione di conflitti di dati per le pubblicazioni di tipo merge (SQL Server Management Studio) e Procedura: Visualizzazione delle informazioni sui conflitti per le pubblicazioni di tipo merge (programmazione Transact-SQL della replica).

Fattori che influenzano la risoluzione dei conflitti

La modalità di risoluzione di un conflitto da parte dell'agente di merge dopo la rilevazione è influenzata da due fattori:

  • Il tipo di sottoscrizione: client o server (il fatto che la sottoscrizione sia pull o push non influisce sulla risoluzione dei conflitti).

  • Il tipo di rilevamento dei conflitti utilizzato: a livello di riga, a livello di colonna o a livello di record logici.

Tipi di sottoscrizioni

Quando si crea una sottoscrizione, oltre a specificare se si tratta di una sottoscrizione push o pull, si specifica se è una sottoscrizione client o server. Dopo aver creato la sottoscrizione, non è più possibile modificarne il tipo (nelle precedenti versioni di Microsoft SQL Server, le sottoscrizioni client e server erano denominate rispettivamente sottoscrizioni locali e globali).

Una sottoscrizione a cui è stata assegnata una priorità (da 0.00 a 99.99) viene denominata sottoscrizione server, mentre una sottoscrizione che utilizza la priorità del server di pubblicazione viene denominata sottoscrizione client. Inoltre, i Sottoscrittori con sottoscrizioni server possono ripubblicare i dati negli altri Sottoscrittori. Nella tabella seguente vengono descritte le differenze e gli utilizzi principali dei due tipi di Sottoscrittore.

Tipo

Valore di priorità

Utilizzo

Server

Assegnato dall'utente

Quando si desidera che Sottoscrittori diversi abbiano priorità diverse.

Client

0.00; le modifiche ai dati assumono però il valore di priorità del server di pubblicazione dopo la sincronizzazione

Quando si desidera che tutti i Sottoscrittori abbiano la stessa priorità e prevalga il primo Sottoscrittore che esegue il processo di merge con il server di pubblicazione.

Se viene modificata una riga in una sottoscrizione client, alla modifica non viene assegnata alcuna priorità fino alla sincronizzazione della sottoscrizione. Durante la sincronizzazione, alle modifiche provenienti dal Sottoscrittore viene assegnata la priorità del server di pubblicazione e queste mantengono tale priorità per le successive sincronizzazioni. In un certo senso, il server di pubblicazione diventa il proprietario della modifica. Questo comportamento permette al primo Sottoscrittore di sincronizzarsi con il server di pubblicazione in modo da prevalere nei successivi conflitti con altri Sottoscrittori per una specifica riga o colonna.

Quando viene modificata una riga in una sottoscrizione server, la priorità della sottoscrizione viene archiviata nei metadati per la modifica. Al momento dell'esecuzione del merge con le modifiche degli altri Sottoscrittori, la riga modificata viene trasferita con questo valore di priorità. In tal modo si garantisce che una modifica eseguita da una sottoscrizione con priorità inferiore non prevalga su una modifica eseguita da una sottoscrizione con priorità superiore.

Una sottoscrizione non può avere un valore di priorità esplicito superiore a quello del proprio server di pubblicazione. Il server di pubblicazione di massimo livello in una topologia di replica di tipo merge ha sempre un valore esplicito di priorità pari a 100.00. Tutte le sottoscrizioni a tale pubblicazione devono avere un valore di priorità inferiore a tale valore. In una topologia di ripubblicazione:

  • Se il Sottoscrittore ripubblica i dati, la sottoscrizione deve essere una sottoscrizione server con valore di priorità inferiore a quella del server di pubblicazione al di sopra del Sottoscrittore.

  • Se il Sottoscrittore non ripubblica i dati (poiché è al livello foglia dell'albero di ripubblicazione) la sottoscrizione deve essere di tipo client.

Per ulteriori informazioni sulla sottoscrizioni server e sulle priorità, vedere Esempio di risoluzione dei conflitti di merge in base al tipo di sottoscrizione e alle priorità assegnate.

Notifica ritardata dei conflitti

La notifica ritardata dei conflitti può verificarsi nel caso di sottoscrizioni server con diverse priorità di conflitto. Si consideri lo scenario seguente: tra il server di pubblicazione e un Sottoscrittore di priorità inferiore vengono scambiate modifiche non in conflitto, che entrano in conflitto quando un Sottoscrittore di priorità superiore si sincronizza con il server di pubblicazione.

  1. Il server di pubblicazione e un Sottoscrittore di bassa priorità, denominato LowPrioritySub, scambiano le modifiche in più sincronizzazioni senza conflitti.

  2. Un Sottoscrittore di priorità superiore, denominato HighPrioritySub, non si è sincronizzato con il server di pubblicazione per un certo periodo, ed ha apportato modifiche alle stesse righe modificate dal Sottoscrittore LowPrioritySub.

  3. Il Sottoscrittore HighPrioritySub si sincronizza con il server di pubblicazione e prevale nei conflitti tra le proprie modifiche e quelle del Sottoscrittore LowPrioritySub, poiché ha una priorità superiore. Il server di pubblicazione contiene ora le modifiche apportate dal Sottoscrittore HighPrioritySub.

  4. Il Sottoscrittore LowPrioritySub esegue quindi il merge con il server di pubblicazione e scarica un gran numero di modifiche a causa dei conflitti con il Sottoscrittore HighPrioritySub.

Questa situazione può divenire problematica quando il Sottoscrittore di priorità inferiore ha apportato modifiche alle stesse righe che sono state ignorate in seguito al conflitto. Come risultato, si potrebbe verificare la perdita di tutte le modifiche eseguite da questo Sottoscrittore. Una delle soluzioni del problema potrebbe consistere nel verificare che tutti i Sottoscrittori abbiano uguale priorità, a meno che non si debba decidere diversamente per rispettare una logica di business.

Livello rilevamento

Una modifica di dati si qualifica come conflitto a seconda del tipo di rilevamento dei conflitti impostato per un articolo: a livello di riga, a livello di colonna o a livello di record logici. Per ulteriori informazioni sul rilevamento a livello di record logici, vedere Rilevamento e risoluzione dei conflitti nei record logici.

Quando i conflitti sono rilevati a livello di riga, le modifiche apportate alle righe corrispondenti vengono riconosciute come conflitti, indipendentemente dal fatto che siano state apportate o meno nella stessa colonna. Si supponga, ad esempio, che venga modificata la colonna dell'indirizzo di una riga del server di pubblicazione e che una seconda modifica venga apportata alla colonna del numero di telefono nella riga corrispondente della stessa tabella nel Sottoscrittore. Se si utilizza il rilevamento a livello di riga, viene rilevato un conflitto in quanto sono state apportate modifiche alla stessa riga. Se si utilizza il rilevamento a livello di colonna, non viene rilevato alcun conflitto in quanto le modifiche sono state apportate in colonne diverse della stessa riga.

Per il rilevamento a livello di riga e a livello di colonna, il processo di risoluzione dei conflitti è sempre lo stesso: l'intera riga di dati viene sovrascritta dalla riga che ha prevalso nel conflitto (per il rilevamento a livello di record logici, la risoluzione dipende dalla proprietà dell'articolo logical_record_level_conflict_resolution).

In genere, l'opzione di rilevamento da utilizzare viene determinata dalla semantica dell'applicazione. Se, ad esempio, si esegue l'aggiornamento di dati di clienti che di norma vengono immessi contemporaneamente, come indirizzi o numeri telefonici, è consigliabile scegliere il rilevamento a livello di riga. Se in questa situazione viene scelto il rilevamento a livello di colonna, le modifiche apportate all'indirizzo del cliente in un sito e quelle apportate al numero telefonico del cliente in un altro sito non vengono rilevate come conflitto, i dati vengono uniti durante la sincronizzazione e l'errore non viene rilevato. In altre situazioni, la soluzione ottimale potrebbe essere l'aggiornamento di singole colonne da siti diversi. Ad esempio, due siti possono avere accesso a informazioni statistiche diverse relative a un cliente, quali il livello di reddito e l'importo totale degli acquisti tramite carta di credito. Il rilevamento a livello di colonna garantisce che in entrambi i siti sia possibile immettere dati statistici per colonne diverse senza generare conflitti inutili.

Nota

Se l'applicazione non richiede il rilevamento a livello di colonna, è consigliabile utilizzare il rilevamento a livello di riga (impostazione predefinita) perché in genere offre prestazioni di sincronizzazione migliori. Se viene utilizzato il rilevamento a livello di riga, la tabella di base può contenere al massimo 1024 colonne, ma le colonne devono essere filtrate dall'articolo affinché venga pubblicato un massimo di 246 colonne. Se viene utilizzato il rilevamento a livello di colonna, la tabella di base può contenere al massimo 246 colonne.

Tipi di conflitti

Sebbene la maggioranza dei conflitti si riferisca agli aggiornamenti (un aggiornamento in un nodo è in conflitto con un aggiornamento o con un'eliminazione in un altro nodo), esistono altri tipi di conflitti. Ogni tipo di conflitto descritto in questa sezione può verificarsi durante la fase di caricamento o di download dell'elaborazione di processi merge. L'elaborazione di caricamento è la prima riconciliazione delle modifiche eseguite in una particolare sessione di merge ed è la fase in cui l'agente di merge replica le modifiche del Sottoscrittore nel server di pubblicazione. I conflitti rilevati durante questa elaborazione vengono denominati conflitti di caricamento. Nell'elaborazione di download le modifiche vengono trasmesse dal server di pubblicazione al Sottoscrittore e questa ha luogo dopo l'elaborazione di caricamento. I conflitti rilevati durante questa fase di elaborazione vengono denominati conflitti di download.

Per ulteriori informazioni sui tipi di conflitti, vedere MSmerge_conflicts_info (Transact-SQL), in particolare le colonne conflict_type e reason_code.

Conflitti aggiornamento-aggiornamento

L'agente di merge rileva i conflitti aggiornamento-aggiornamento quando l'aggiornamento di una riga (o colonna o record logico) in un nodo è in conflitto con un altro aggiornamento della stessa riga in un altro nodo. Il comportamento del sistema di risoluzione predefinito in questo caso prevede l'invio della versione della riga che ha prevalso al nodo della riga perdente e la registrazione di quest'ultima nella tabella dei conflitti dell'articolo.

Conflitti aggiornamento-eliminazione

L'agente di merge rileva i conflitti aggiornamento-eliminazione quando l'aggiornamento di dati in un nodo è in conflitto con un'eliminazione in un altro nodo. In questo caso, l'agente di merge aggiorna una riga; tuttavia, quando ricerca la stessa riga nella destinazione, non la trova perché è stata eliminata. Se ha prevalso il nodo che ha aggiornato la riga, l'eliminazione nell'altro nodo viene ignorata e l'agente di merge invia la riga appena aggiornata al nodo di quella eliminata, quindi registra le informazioni sulla versione perdente della riga nella tabella MSmerge_conflicts_info.

Conflitti di modifica non riuscita

L'agente di merge genera questi conflitti quando non è in grado di applicare una particolare modifica. In genere, questo accade a causa di una differenza tra le definizioni dei vincoli nel server di pubblicazione e nel Sottoscrittore e per il diverso uso della proprietà NOT FOR REPLICATION (NFR) nel vincolo. Esempi di tali situazioni:

  • Un conflitto di chiave esterna nel Sottoscrittore, che può verificarsi quando il vincolo del lato Sottoscrittore non è contrassegnato come NFR.

  • Differenze di vincoli tra server di pubblicazione e Sottoscrittori, e mancato contrassegno dei vincoli come NFR.

  • Indisponibilità di oggetti dipendenti nel Sottoscrittore. Ad esempio, se si pubblica una vista ma non la tabella dalla quale dipende, se si tenta di inserirsi nel Sottoscrittore attraverso la vista si verifica un errore.

  • Logica di filtraggio join per una pubblicazione che non corrisponde ai vincoli di chiave primaria e di chiave esterna. Possono verificarsi dei conflitti quando il motore relazionale di SQL Server prova a rispettare un vincolo ma l'agente di merge rispetta la definizione di filtro join tra articoli. L'agente di merge non può applicare la modifica nel nodo di destinazione a causa dei vincoli a livello di tabella, cosa che genera un conflitto.

  • È possibile che si verifichino conflitti a causa di violazioni di indice univoco, vincolo univoco o chiave primaria se per l'articolo vengono definite colonne Identity e non viene utilizzata la gestione automatica delle identità. Questo può essere un problema se due Sottoscrittori utilizzano lo stesso valore Identity per una riga appena inserita. Per ulteriori informazioni sulla gestione degli intervalli di valori Identity, vedere Replica di colonne Identity.

  • Conflitti dovuti a una logica di trigger che impedisce all'agente di merge di inserire una riga nella tabella di destinazione. Si consideri un trigger di aggiornamento definito nel Sottoscrittore, che non è contrassegnato come NFR e nella propria logica include un ROLLBACK. In caso di errore, il trigger esegue un rollback della transazione e di conseguenza l'agente di merge rileva un conflitto di modifica non riuscita.