Guida alla migrazione da Oracle a SQL Server e da SQL Server a Oracle - Pt. 3
Pubblicato: 2022-03-11La prima e la seconda parte di questa serie hanno discusso le differenze tra Oracle Database e Microsoft SQL Server nell'implementazione delle transazioni e le insidie di conversione risultanti, nonché alcuni elementi di sintassi comunemente usati.
Quest'ultima puntata tratterà la nozione di coerenza di lettura di Oracle e come convertire l'architettura, basata su questa nozione, in una versione di Microsoft SQL Server. Tratterà anche l'uso dei sinonimi (e come NON usarli) e il ruolo del processo di controllo delle modifiche nella gestione dell'ambiente del database.
Coerenza di lettura di Oracle e suo equivalente in SQL Server
La coerenza di lettura di Oracle garantisce che tutti i dati restituiti da una singola istruzione SQL provengano dallo stesso singolo momento.
Significa che se hai emesso un'istruzione SELECT
alle 12:01:02.345 ed è stata eseguita per 5 minuti prima di restituire il set di risultati, tutti i dati (e solo i dati) di cui è stato eseguito il commit nel database a partire dalle 12:01:02.345 lo faranno nel tuo set di ritorno. Il tuo set di reso non avrà nuovi dati aggiunti durante quei 5 minuti che hanno impiegato il database per elaborare la tua dichiarazione, né alcun aggiornamento e nessuna eliminazione sarà visibile.
L'architettura Oracle ottiene la coerenza della lettura mediante il timestamp interno di ogni modifica ai dati e la creazione di un set di risultati da due origini: file di dati permanenti e un segmento di annullamento (o "segmento di rollback", come era noto fino alla versione 10g).
Per supportarlo, le informazioni sull'annullamento dovrebbero essere conservate. Se viene sovrascritto, risulta nel famigerato errore ORA-01555: snapshot too old
.
Lasciando da parte la gestione del segmento di annullamento e come navigare ORA-01555: snapshot too old
, esaminiamo le implicazioni della coerenza di lettura su qualsiasi implementazione pratica in Oracle. Inoltre, come dovrebbe essere eseguito il mirroring in SQL Server, che, come nel caso di altre implementazioni RDBMS, con la possibile e qualificata eccezione di PostgreSQL, non lo supporta?
La chiave è che Oracle legge e scrive non si bloccano a vicenda. Significa anche che il tuo set di query restituite di lunga durata potrebbe non avere i dati più recenti.
Le letture e le scritture non bloccanti sono un vantaggio di Oracle e influiscono sull'ambito delle transazioni.
Ma la coerenza di lettura significa anche che non si dispone dell'ultimo stato dei dati. Quando in alcuni scenari è perfettamente valido (come la produzione di un rapporto per un determinato periodo), in altri potrebbe creare problemi significativi.
Non disporre dei dati più recenti, anche "sporchi" o non vincolati, potrebbe essere fondamentale: lo scenario classico è un sistema di prenotazione di camere d'albergo.
Considera il seguente caso d'uso: hai due agenti del servizio clienti che accettano contemporaneamente ordini di prenotazione di camere. Come puoi assicurarti che le camere non diventino overbooking?
In SQL Server è possibile avviare una transazione esplicita e SELECT
un record dall'elenco (che potrebbe essere una tabella o una vista) delle stanze disponibili. Finché questa transazione non viene chiusa (né da COMMIT
o ROLLBACK
), nessuno può ottenere lo stesso record della stanza che hai selezionato. Ciò impedisce la doppia prenotazione ma fa anche attendere che ogni altro agente completi le richieste di prenotazione una alla volta, in sequenza.
In Oracle, puoi ottenere lo stesso risultato emettendo un'istruzione SELECT ... FOR UPDATE
rispetto ai record che corrispondono ai tuoi criteri di ricerca.
Nota: esistono soluzioni migliori, come impostare un contrassegno temporaneo che contrassegna una stanza "in esame" invece di bloccarne l'accesso alla cieca. Ma quelle sono soluzioni architettoniche, non opzioni linguistiche.
Conclusione : la coerenza della lettura di Oracle non è "tutto buono" o "tutto cattivo", ma una proprietà importante della piattaforma che deve essere compresa bene ed è fondamentale per la migrazione del codice multipiattaforma.
Sinonimi pubblici (e privati) in Oracle e Microsoft SQL Server
"I sinonimi pubblici sono malvagi". Non è esattamente una mia scoperta personale, ma l'ho accettato come vangelo fino a quando il mio giorno, settimana e anno non sono stati salvati da sinonimi pubblici.
In molti ambienti di database, direi tutti gli ambienti Oracle con cui ho avuto la possibilità di lavorare, ma nessuno che ho progettato, l'uso di CREATE PUBLIC SYNONYM
per ogni oggetto era una routine perché "l'abbiamo sempre fatto in questo modo".
In questi ambienti, i sinonimi pubblici avevano una sola funzione: consentire il riferimento a un oggetto senza specificarne il proprietario. E questa è una ragione poco ponderata per rendere pubblici i sinonimi.
Tuttavia, i sinonimi pubblici di Oracle possono essere estremamente utili e offrire vantaggi in termini di produttività del team che superano in modo significativo tutti i loro svantaggi, se implementati e gestiti correttamente e con un motivo. Sì, ho detto "produttività del team". Ma come? Per questo, dobbiamo capire come funziona la risoluzione dei nomi in Oracle.
Quando il parser Oracle trova un nome (una parola chiave non riservata), tenta di abbinarlo a un oggetto di database esistente nel seguente ordine:
Nota: l'errore generato sarà ORA-00942: table or view does not exist
per le istruzioni DML oppure PLS-00201: identifier 'my_object' must be declared
per le procedure memorizzate o le chiamate di funzione.
In questo ordine di risoluzione dei nomi, è facile vedere che quando uno sviluppatore lavora nel proprio schema, qualsiasi oggetto locale con lo stesso nome di un sinonimo pubblico nasconderà questo sinonimo pubblico. (Nota: Oracle 18c ha implementato il tipo di schema "solo accesso" e questa discussione non si applica ad esso.)
Sinonimi pubblici per i team di ridimensionamento: Oracle Change Control
Diamo ora un'occhiata a un ipotetico team di 100 sviluppatori che lavorano sullo stesso database (che è qualcosa che ho sperimentato). Inoltre, supponiamo che lavorino tutti in locale sulle loro workstation personali e che eseguano build non di database in modo indipendente, tutti collegati allo stesso ambiente di sviluppo del database. La risoluzione dell'unione del codice in codice non di database (che si tratti di C#, Java, C++, Python o qualsiasi altra cosa) verrà eseguita al momento del check-in del controllo delle modifiche e avrà effetto con la successiva build del codice. Ma le tabelle del database, il codice e i dati devono essere modificati più volte durante lo sviluppo in corso. Ogni sviluppatore lo fa in modo indipendente e ha effetto immediatamente.
Per questo, tutti gli oggetti di database vengono creati in uno schema di applicazione comune. Questo è lo schema a cui fa riferimento l'applicazione. Ogni sviluppatore:
- Si collega al database con il proprio account utente/schema personale
- Inizia sempre con uno schema personale vuoto
- Fa riferimento allo schema comune solo tramite la risoluzione dei nomi a un sinonimo pubblico, come descritto sopra
Quando uno sviluppatore deve apportare modifiche al database, creare o modificare una tabella, modificare il codice della procedura o persino modificare un insieme di dati per supportare uno scenario di test, crea una copia dell'oggetto nel proprio schema personale. Lo fanno ottenendo il codice DDL usando il comando DESCRIBE
ed eseguendolo localmente.
Da questo momento, il codice di questo sviluppatore vedrà la versione locale dell'oggetto e dei dati, che non sarà visibile (né avrà un impatto su) nessun altro. Al termine dello sviluppo, il codice del database modificato viene archiviato nel controllo del codice sorgente e i conflitti vengono risolti. Quindi, il codice finale (e i dati, se necessario) vengono implementati nello schema comune.
Dopodiché, l'intero team di sviluppo può vedere di nuovo lo stesso database. Lo sviluppatore che ha appena consegnato il codice elimina tutti gli oggetti dal suo schema personale ed è pronto per un nuovo incarico.
Questa capacità di facilitare il lavoro parallelo indipendente per più sviluppatori è il principale vantaggio dei sinonimi pubblici, un'importanza difficile da sopravvalutare. Tuttavia, in pratica, continuo a vedere team che creano sinonimi pubblici nelle implementazioni Oracle "solo perché lo facciamo sempre". Al contrario, nei team che utilizzano SQL Server, non vedo la creazione di sinonimi pubblici come una pratica comune. La funzionalità esiste ma non viene utilizzata spesso.
In SQL Server, lo schema predefinito corrente per un utente è definito nella configurazione utente e può essere modificato in qualsiasi momento se si dispone dei privilegi di "alterazione utente". È possibile implementare la stessa esatta metodologia descritta sopra per Oracle. Tuttavia, se questo metodo non viene utilizzato, i sinonimi pubblici non devono essere copiati.
Poiché Microsoft SQL Server non associa un nuovo account utente al proprio schema per impostazione predefinita (come fa Oracle), l'associazione dovrebbe far parte dello script "crea utente" standard.
Di seguito è riportato un esempio di uno script che crea schemi utente dedicati e ne assegna uno a un utente.
Innanzitutto, crea schemi per i nuovi utenti che devono essere inseriti nel database denominato DevelopmentDatabase
(ogni schema deve essere creato nel proprio batch):
use DevelopmentDatabase; GO CREATE SCHEMA Dev1; GO CREATE SCHEMA Dev2; GO
In secondo luogo, crea il primo utente con lo schema predefinito assegnato:
CREATE LOGIN DevLogin123 WITH PASSWORD = 'first_pass123'; CREATE USER Dev1 FOR LOGIN DevLogin123 WITH DEFAULT_SCHEMA = Dev1; GO
A questo punto, lo schema predefinito per l'utente Dev1
sarebbe Dev1
.
Quindi, crea l'altro utente senza schema predefinito:
CREATE LOGIN DevLogin321 WITH PASSWORD = 'second_pass321'; CREATE USER Dev2 FOR LOGIN DevLogin321; GO
Lo schema predefinito per l'utente Dev2
è dbo
.
Ora modifica l'utente Dev2
per cambiare il suo schema predefinito in Dev2
:
ALTER USER Dev2 WITH DEFAULT_SCHEMA = Dev2; GO
Ora lo schema predefinito per l'utente Dev2
è Dev2
.
Questo script illustra due modi per assegnare e modificare uno schema predefinito per un utente nei database di Microsoft SQL Server. Poiché SQL Server supporta più metodi di autenticazione dell'utente (il più comune è l'autenticazione di Windows) e l'onboarding degli utenti può essere gestito dagli amministratori di sistema anziché dai DBA, il metodo ALTER USER
per l'assegnazione/modifica dello schema predefinito sarà più utilizzabile.
Nota: ho reso il nome dello schema uguale al nome di un utente. Non deve essere così in SQL Server, ma è la mia preferenza perché (1) corrisponde a come è fatto in Oracle e (2) semplifica la gestione degli utenti (rispondendo alla più grande obiezione da parte di un DBA per farlo bene in primo luogo) — conosci il nome di un utente e conosci automaticamente lo schema predefinito dell'utente.
Conclusione : i sinonimi pubblici sono uno strumento importante per costruire un ambiente di sviluppo multiutente stabile e ben protetto. Sfortunatamente, secondo la mia osservazione nel settore, è più spesso usato per le ragioni sbagliate, lasciando i team a soffrire la confusione e altri aspetti negativi dei sinonimi pubblici senza rendersi conto dei loro vantaggi. Modificare questa pratica per trarre vantaggi reali dai sinonimi pubblici può apportare vantaggi reali al flusso di lavoro di sviluppo di un team.

Gestione degli accessi al database e processi di gestione delle modifiche
Poiché abbiamo appena parlato del supporto per lo sviluppo parallelo da parte di grandi team, vale la pena affrontare un argomento separato e spesso frainteso: i processi di controllo del cambiamento.
La gestione del cambiamento diventa spesso una forma di burocrazia controllata dai responsabili del team e dai DBA, disprezzata dagli sviluppatori ribelli che vogliono fornire tutto se non "ieri" poi "ora".
In qualità di DBA, metto sempre barriere protettive nel "mio" database. E ho un'ottima ragione per questo: un database è una risorsa condivisa.
Twitta
In un contesto di controllo del codice sorgente, la gestione delle modifiche è generalmente accettata poiché consente a un team di tornare da codice nuovo ma non funzionante a codice vecchio ma funzionante. Ma in un contesto di database, la gestione del cambiamento può sembrare un insieme di barriere e restrizioni irragionevoli poste dai DBA: è pura follia che rallenta inutilmente lo sviluppo!
Lasciamo da parte lo sfogo di questo sviluppatore: sono un DBA e non mi lancerò sassi! In qualità di DBA, metto sempre barriere protettive nel "mio" database. E ho un'ottima ragione per questo: un database è una risorsa condivisa.
Ogni team di sviluppo, e ciascuno dei suoi sviluppatori, ha un obiettivo definito in modo molto specifico e un deliverable molto specifico. L'unico obiettivo che si trova sulla scrivania di un DBA ogni giorno è la stabilità del database come risorsa condivisa. Un DBA ha il ruolo unico in un'organizzazione di supervisionare tutti gli sforzi di sviluppo in tutti i team e di controllare un database a cui accedono tutti gli sviluppatori. È il DBA che garantisce che tutti i progetti e tutti i processi siano in esecuzione senza interferire tra loro e che ciascuno disponga delle risorse necessarie per funzionare.
Il problema è quando entrambi i team di sviluppo e DBA siedono rinchiusi nelle rispettive torri d'avorio.
Gli sviluppatori non lo sanno, non hanno accesso e non si preoccupano nemmeno di cosa succede sul database fintanto che funziona bene per loro. (Non è il loro risultato, né influenzerà la loro valutazione delle prestazioni.)
Il team DBA tiene il database vicino al petto, proteggendolo dagli sviluppatori che "non ne sanno nulla", perché l'obiettivo del loro team è la stabilità del database. E il modo migliore per garantire la stabilità è prevenire modifiche distruttive, che spesso si traducono in un atteggiamento di protezione il più possibile il database da eventuali modifiche.
Questi atteggiamenti contrastanti nei confronti di un database possono, come ho visto, portare all'animosità tra i team di sviluppo e DBA e risultare in un ambiente impraticabile. Ma i DBA e il team di sviluppo devono lavorare insieme per raggiungere un obiettivo comune: fornire una soluzione aziendale, che è ciò che li ha uniti in primo luogo.
Essendo stato su entrambi i lati del divario tra sviluppatori e DBA, so che il problema è facile da risolvere quando i DBA comprendono meglio i compiti e gli obiettivi comuni dei team di sviluppo. Da parte loro, gli sviluppatori devono vedere un database non come un concetto astratto ma come una risorsa condivisa, e lì un DBA dovrebbe assumere il ruolo di educatore.
L'errore più comune commesso dai DBA non per sviluppatori è la limitazione dell'accesso degli sviluppatori al dizionario dei dati e agli strumenti di ottimizzazione del codice. L'accesso alle viste del catalogo Oracle DBA_
, alle viste V$
dinamiche e alle tabelle SYS
sembra a molti DBA come "privilegiato DBA" quando, in realtà, si tratta di strumenti di sviluppo critici.
Lo stesso vale per SQL Server, con una complicazione: l'accesso ad alcune viste di sistema non può essere concesso direttamente, ma è solo una parte del ruolo del database SYSADMIN
e questo ruolo non dovrebbe mai essere concesso al di fuori del team DBA. Questo problema può essere risolto (e dovrebbe essere risolto nel caso di migrazione di un progetto da Oracle a SQL Server) creando viste e stored procedure che vengono eseguite con privilegi SYSADMIN
ma sono accessibili da utenti non DBA. Questo è il lavoro del DBA di sviluppo da eseguire quando viene configurato un nuovo ambiente di sviluppo di SQL Server.
La protezione dei dati è una delle principali responsabilità di un DBA. Nonostante ciò, è abbastanza comune per i team di sviluppo avere pieno accesso ai dati di produzione non filtrati per consentire la risoluzione dei problemi relativi ai ticket relativi ai dati. Questi sono gli stessi sviluppatori che hanno un accesso limitato alla struttura dei dati, la struttura che è stata creata da loro o per loro in primo luogo.
Quando vengono stabilite corrette relazioni di lavoro tra i team di sviluppo e DBA, la creazione di un buon processo di controllo delle modifiche diventa intuitiva. Le specifiche e la sfida della gestione delle modifiche lato database sono la rigidità e la fluidità di un database allo stesso tempo: la struttura è rigida, i dati sono fluidi.
Accade spesso che la gestione delle modifiche sulla modifica della struttura, ad esempio sul linguaggio di definizione dei dati o DDL, sia ben consolidata mentre le modifiche ai dati hanno poco o nessuno in termini di gestione delle modifiche. La giustificazione è semplice: i dati cambiano continuamente.
Ma se osserviamo questo aspetto più da vicino, vedremo che in qualsiasi sistema, tutti i dati rientrano in una delle due categorie: dati dell'applicazione e dati dell'utente.
I dati dell'applicazione sono un dizionario di dati che definisce il comportamento di un'applicazione ed è fondamentale per i suoi processi come qualsiasi codice dell'applicazione. Le modifiche a questi dati dovrebbero essere soggette a rigidi processi di controllo delle modifiche, proprio come con qualsiasi altra modifica dell'applicazione. Per creare trasparenza nel processo di controllo delle modifiche per le modifiche ai dati dell'applicazione, i dati dell'applicazione ei dati dell'utente dovrebbero essere separati in modo esplicito.
In Oracle, dovrebbe essere eseguito inserendo i dati dell'applicazione e dell'utente ciascuno nel proprio schema. In Microsoft SQL Server, dovrebbe essere eseguito inserendo ciascuno di essi in uno schema separato o, molto meglio, in un database separato. Fare queste scelte dovrebbe far parte della pianificazione della migrazione: Oracle ha una risoluzione dei nomi a due livelli (schema/proprietario – nome oggetto) mentre SQL Server ha una risoluzione dei nomi a tre livelli (database – schema/proprietario – nome oggetto).
Una fonte comune di confusione tra i mondi Oracle e SQL Server sono, forse sorprendentemente, i termini database e server :
Termine di SQL Server | Termine Oracolo | Definizione |
---|---|---|
server | database (usato in modo intercambiabile con il server nel linguaggio comune, a meno che non si riferisca specificamente all'hardware del server, al sistema operativo o agli elementi di rete; possono esserci uno o più database su un server fisico/virtuale) | Un'istanza in esecuzione che può "parlare" con altre istanze tramite le porte di rete |
database (parte di un server, contiene più schemi/proprietari) | schema/proprietario | Il raggruppamento di livello più alto |
Questo mix di terminologia dovrebbe essere chiaramente compreso nei progetti di migrazione multipiattaforma perché un'errata interpretazione dei termini può comportare decisioni di configurazione errate che sono difficili da affrontare retroattivamente.
La corretta separazione dei dati dell'applicazione e dell'utente consente a un team DBA di affrontare la sua seconda preoccupazione più importante: la sicurezza dei dati degli utenti. Poiché i dati dell'utente risiedono separatamente, sarà molto semplice implementare una procedura di rottura del vetro per l'accesso ai dati dell'utente in base alle esigenze.
Conclusione : i processi di controllo del cambiamento sono fondamentali in qualsiasi progetto. Nell'ingegneria del software, la gestione delle modifiche lato database viene spesso trascurata perché i dati sono considerati "troppo fluidi". Ma è proprio perché i dati sono "fluidi" e "persistenti" allo stesso tempo che un processo di controllo delle modifiche ben progettato dovrebbe essere la pietra angolare di una corretta architettura dell'ambiente di database.
Sull'uso degli strumenti di migrazione del codice
Gli strumenti proprietari standard, Oracle Migration Workbench e SQL Server Migration Assistant, possono essere utili nelle migrazioni di codice. Ma ciò che deve essere preso in considerazione è la regola 80/20: quando il codice verrà migrato correttamente all'80%, la risoluzione del restante 20% richiederà l'80% dello sforzo di migrazione.
Il rischio maggiore nell'uso degli strumenti di migrazione è di gran lunga la percezione del "proiettile d'argento". Si potrebbe essere tentati di pensare: "Farà il lavoro e dovrò solo fare un po' di pulizia e riordino". Ho osservato un progetto fallito a causa di tale atteggiamento da parte del team di conversione e della sua leadership tecnica.
D'altra parte, mi ci sono voluti quattro giorni lavorativi per realizzare la conversione di base di un sistema Microsoft SQL Server 2008 di medie dimensioni (circa 200 oggetti) utilizzando la funzionalità di sostituzione in blocco di Notepad++ come strumento di modifica principale.
Nessuno degli elementi critici della migrazione che ho affrontato finora può essere risolto dagli strumenti di migrazione.
Certo, usa gli strumenti di assistenza alla migrazione, ma ricorda che questi forniscono solo assistenza per la modifica. Il testo di output risultante deve essere revisionato, modificato e, in alcuni casi, riscritto per diventare codice degno di produzione.
Lo sviluppo di strumenti di intelligenza artificiale potrebbe affrontare queste carenze degli strumenti di migrazione in futuro, ma mi aspetto che le differenze tra i database svaniscano prima di allora e qualsiasi processo di migrazione stesso diventi superfluo. Quindi, finché saranno necessari questi tipi di progetti, dovremo farlo alla vecchia maniera, usando l'intelligenza umana vecchio stile.
Conclusione : l'utilizzo degli strumenti di assistenza alla migrazione è utile ma non è un "proiettile d'argento" e qualsiasi progetto di conversione richiede comunque una revisione dettagliata dei punti precedenti.
Migrazioni Oracle/SQL Server: dai un'occhiata più da vicino
Oracle e Microsoft SQL Server sono le due piattaforme RDBMS più diffuse nell'ambiente aziendale. Entrambi hanno una conformità di base allo standard ANSI SQL e piccoli segmenti di codice possono essere spostati con pochissime modifiche o addirittura così com'è.
Questa somiglianza crea l'impressione ingannevole che la migrazione tra le due piattaforme sia un'attività semplice e diretta e che la stessa applicazione possa essere facilmente adottata dall'utilizzo di un back-end RDBMS a un altro.
In pratica, tali migrazioni di piattaforme sono tutt'altro che banali e devono tenere conto degli elementi fini del funzionamento interno di ciascuna piattaforma e, soprattutto, del modo in cui implementano il supporto per l'elemento più critico della gestione dei dati: le transazioni.
Anche se ho trattato due piattaforme RDBMS che sono al centro della mia esperienza, lo stesso avviso - "si assomiglia non significa che funzioni allo stesso modo" - dovrebbe essere applicato allo spostamento del codice tra qualsiasi altro sistema di gestione di database conforme a SQL. E in tutti i casi, il primo punto di attenzione dovrebbe essere su come l'implementazione della gestione delle transazioni differisce tra la piattaforma di origine e quella di destinazione.