... Come evitare l' uso dei cursori?

mercoledì 29 giugno 2011 - 15.54
Tag Elenco Tags  SQL Server 2005

Gekone Profilo | Newbie

Buobasera a tutti,

dopo molto tempo che leggo i suggerimenti su questo forum mi trovo a chiederne uno, in questo primo post! :)

Questo è lo scenario: gestionale in azienda che si appoggia al dbms sql 2005 server. Le aziende configurate sono tre, per questo vengono usati tre diversi database.
Ora, trattandosi delle stesse persone che gestiscono queste tre aziende capita spesso di creare dei meccanismi di soncronizzazione fra i tre database.
Oggi mi trovo a creare un trigger after insert per replicare l' inserimento di un articolo, nella tabella AR (dell'anagrafica a rticoli) delle altre due aziende (poiché l' inserimento è previsto in un unica azienda).
Visto che queste aziende fanno parte di un gruppo destinato a creascere, prefrisco parametrizzare i database da sincronizzare in modo che all' aggiunta di una nuova azienda non debba far altro che inserire il nome del database in una tabella (che ho chiamato "xSyncDB" e che contiene solo la colonna "DbName".

Il trigger che ho provato è questo(riporto solo il pezzo fondamentale):

Il codice sorgente non è stato renderizzato qui
perchè non c'è sufficiente spazio.
Clicca qui per visualizzarlo in una nuova finestra

In questo modo non uso i cursori, ma se devo creare un' azienda nuova, dovrei modificare il trigger ed aggiungere l' istruzione di insert anche per essa.

Quello che ho provato a fare è inserire in un cursore i nomi dei database prelevati da "xSyncDB", in un altro ho inserito i record della tabella inserted e con due itarazioni annidate eseguo l' insert record per record per ogni database con exec: come è possibile migliorare in termini di efficienza(i cursori mi stanno proprio indigesti :) ) ?

Grazie in anticipo per i consigli.

micto27 Profilo | Senior Member

Ciao,

così senza conoscere bene lo scenario e immaginando che i vari server di cui parli siano "remoti" tra di loro, mi lascia un attimo perplesso
la scelta del TRIGGER in quanto, soprattutto se poi i server aumentassero, vincola la transazione di inserimento al fatto che tutti i server coinvolti
siano disponibili. Se uno di questi non lo fosse, per problemi di connettività o manutenzione, ecc., l'inserimento dell'articolo fallirebbe per tutti (quindi.
può anche essere che tale scelta tu l'abbia fatta apposta per questo motivo)....

Avevi già valutato la soluzione di una replica, asincrona rispetto alla transazione, sfruttando i sistemi di replica forniti da SQL Server?

Potresti avere il database principale che espone la replica di una serie di aggetti (es. la tabella Articoli), ogni server "secondario" si iscriverebbe a tale replica.
Quindi, alla definizione di un nuovo server secondario, si tratterebbe di eseguire (via script) la sottoscrizione alla replica in questione.

Se tale replica fosse di tipo "Transactional" (le altre tipologie che ricordo sono Snapshot e Merge) otterresti che ogni operazione effettuata sul master
verrebbe riprodotta sui server "iscritti" o al momento o ad esempio ogni n minuti, ecc.

Michele

Gekone Profilo | Newbie

Ciao,
>
>così senza conoscere bene lo scenario e immaginando che i vari
>server di cui parli siano "remoti" tra di loro, mi lascia un
>attimo perplesso
>la scelta del TRIGGER in quanto, soprattutto se poi i server
>aumentassero, vincola la transazione di inserimento al fatto
>che tutti i server coinvolti
>siano disponibili. Se uno di questi non lo fosse, per problemi
>di connettività o manutenzione, ecc., l'inserimento dell'articolo
>fallirebbe per tutti (quindi.
>può anche essere che tale scelta tu l'abbia fatta apposta per
>questo motivo)....
>

Come avevo detto le tre aziende usano tre database distinti ma devo aggiungere, visto che l' avevo tralasciato, che
i tre database si trovano sulla stessa istanza sql 2005 in un unico server.

>Avevi già valutato la soluzione di una replica, asincrona rispetto
>alla transazione, sfruttando i sistemi di replica forniti da
>SQL Server?
>
>Potresti avere il database principale che espone la replica di
>una serie di aggetti (es. la tabella Articoli), ogni server "secondario"
>si iscriverebbe a tale replica.
>Quindi, alla definizione di un nuovo server secondario, si tratterebbe
>di eseguire (via script) la sottoscrizione alla replica in questione.
>
>Se tale replica fosse di tipo "Transactional" (le altre tipologie
>che ricordo sono Snapshot e Merge) otterresti che ogni operazione
>effettuata sul master
>verrebbe riprodotta sui server "iscritti" o al momento o ad esempio
>ogni n minuti, ecc.
>
Visto che devo sincronizzare solo alcuni attributi (con delle eventuali conversioni - cioè ad esempio, l' attributo "A" se ha valore 1 per un'azienda potrei doverlo convertire in 2 per un' altra e lasciarlo ad 1 per l'altra ancora) preferisco usare un unico trigger sull' azienda in cui vengono gestiti (in termini di inserimento, aggiornamento e cancellazione) gli articoli.

Riporto il trigger completo, cosi magari mi potete suggerire se c'è un modo per ovviare ai cursori.

Il codice sorgente non è stato renderizzato qui
perchè non c'è sufficiente spazio.
Clicca qui per visualizzarlo in una nuova finestra



Grazie Michele!
>Michele

micto27 Profilo | Senior Member

Mi chiedevo una cosa (non so se nel tuo caso è applicabile).

Se lo scenario (sullo stessa istanza Sql Server) è
# database principale
# database secondario 1
# database secondario 2
# database secondario n

e per quanto riguarda gli ARTICOLI fa fede il "database principale" non basterebbe fare in modo
che su tutti i database "secondari" anzichè avere la tabella ARTICOLI avere invece una vista con lo stesso nome ARTICOLI
che punti direttamente alla tabella articoli del db principale?

Non servirebbe alcun trigger e gli articoli sarebbero fisicamente solo da una parte.

Diversamente io opterei per una "replica transazionale".

Ciao, Michele

Gekone Profilo | Newbie

>Mi chiedevo una cosa (non so se nel tuo caso è applicabile).
>
>Se lo scenario (sullo stessa istanza Sql Server) è
># database principale
># database secondario 1
># database secondario 2
># database secondario n
>
>e per quanto riguarda gli ARTICOLI fa fede il "database principale"
>non basterebbe fare in modo
>che su tutti i database "secondari" anzichè avere la tabella
>ARTICOLI avere invece una vista con lo stesso nome ARTICOLI
>che punti direttamente alla tabella articoli del db principale?
>
>Non servirebbe alcun trigger e gli articoli sarebbero fisicamente
>solo da una parte.
>
>Diversamente io opterei per una "replica transazionale".
>
>Ciao, Michele
>

Purtroppo non tutti gli attributi devono essere sincronizzati: solo quelli specificati nel trigger gli altri devono impostati nell' azienda specifica (ad esempio scorta minima e scorta massima della giacenza!)
Per la vista non saprei, penso che il gestionale "si arrabbi" abbastanza lavorando sulla vista ...

Ma soluzioni per eliminare l' uso dei cursori nel trigger che ho riportato sul post precedente non ci sono proprio?
Potrei anche usare quello, ricopre a pieno le mie esigenza, solo che avrei voluto (anche solo per curiosità visto che sono rare le operazioni sull' anagrafica articoli) perlomeno sapere se esiste un metodo per non usare i cursori, nel mio caso.

Grazie ancora.
Ciao.

micto27 Profilo | Senior Member

in effetti non avevo capito che non andavi ad agire su tutte le colonne della tabella.

Se le cose stanno come dici non vedo molte alternative, e in ogni caso non mi scandalizza un cursore del genere,
non si tratta di ciclare su grandi quantità di dati.

Forse, per semplificare un po' potresti valutare di avere un unica gestione del cursore
differenziando all'interno di questo se si tratta di INSERT, UPDATE o DELETE.
Si accorcerebbe un po' visto che più o meno cambia solo il tipo di comando che vai a costruire ed eseguire,
però il ciclo sui databases e il resto mi sembrano sovrapponibili.

Diversamente dovresti esplicitare le operazioni sui vari db e cambiare il trigger ogni volta che si andasse ad aggiungere un nuovo db.

Ciao

Gekone Profilo | Newbie

>in effetti non avevo capito che non andavi ad agire su tutte
>le colonne della tabella.
A dir il vero non lo avevo esplicitato!
>
>Se le cose stanno come dici non vedo molte alternative, e in
>ogni caso non mi scandalizza un cursore del genere,
>non si tratta di ciclare su grandi quantità di dati.
>
No infatti, per ora al 99% degli insert parliamo di 3 aziende ed 1 articolo.

A questo proposito vorrei chiedervi se è conveniente in termini di efficienza controllare se c'è solo un record da inserire, aggiornare o eliminare ed in questo caso evitare un cursore e tenendo solo quello delle aziende. A rigor di logica dovrebbe essere più efficiente questo modo, no?

>Forse, per semplificare un po' potresti valutare di avere un
>unica gestione del cursore
>differenziando all'interno di questo se si tratta di INSERT,
>UPDATE o DELETE.
>Si accorcerebbe un po' visto che più o meno cambia solo il tipo
>di comando che vai a costruire ed eseguire,
>però il ciclo sui databases e il resto mi sembrano sovrapponibili.
>
Avevo valutato questa alternativa, ma l' avevo abbandonata perché pensavo che fosse più difficile (essendo il codice meno leggibile) eseguire delle eventuali modifiche al trigger fra qualche tempo...

>Diversamente dovresti esplicitare le operazioni sui vari db e
>cambiare il trigger ogni volta che si andasse ad aggiungere un
>nuovo db.
>
>Ciao

Ciao e grazie!

micto27 Profilo | Senior Member

Comunque se il cursore sui database non è evitabile
quello interno sulle righe probabilmente si.

Es. in caso di insert dovrebbe funzionare il comando da costruirsi come

'INSERT INTO tabella (a, b, c, d, e, f, ...)
SELECT a1, b1, c1, d1, e1, f1, ....
FROM inserted'

per delete
'DELETE FROM tabella where id_articolo in (select id_articolo from deleted)'

per update
'UPDATE tabella set tabella.a = i.a, tabella.b = i.b
from inserted i
where i.id_articolo = tabella.id_articolo'


sono andato a memoria, spero di non aver scritto sbagliato però eventualmente
si tratta solo di limare un po'

Mi viene il dubbio se questa soluzione è compatibile con i comandi in sql dinamico, però se funzionasse forse potresti usarla
eliminando il cursore sui database ed eseguendo puntualmente l'aggiornamento dei 2, 3 db secondari


Ciao
Partecipa anche tu! Registrati!
Hai bisogno di aiuto ?
Perchè non ti registri subito?

Dopo esserti registrato potrai chiedere
aiuto sul nostro Forum oppure aiutare gli altri

Consulta le Stanze disponibili.

Registrati ora !
Copyright © dotNetHell.it 2002-2017
Running on Windows Server 2008 R2 Standard, SQL Server 2012 & ASP.NET 3.5