Guía de migración de Oracle a SQL Server y de SQL Server a Oracle - Pt. 3

Publicado: 2022-03-11

La primera y la segunda parte de esta serie analizan las diferencias entre Oracle Database y Microsoft SQL Server en la implementación de las transacciones y los errores de conversión resultantes, así como algunos elementos de sintaxis de uso común.

Esta última entrega cubrirá la noción de consistencia de lectura de Oracle y cómo convertir la arquitectura, basada en esta noción, en una versión de Microsoft SQL Server. También abordará el uso de sinónimos (y cómo NO usarlos) y el papel del proceso de control de cambios en la gestión de su entorno de base de datos.

Consistencia de lectura de Oracle y su equivalente en SQL Server

La consistencia de lectura de Oracle es una garantía de que todos los datos devueltos por una sola instrucción SQL provienen del mismo punto singular en el tiempo.

Significa que si emitió una declaración SELECT a las 12:01:02.345 y se ejecutó durante 5 minutos antes de devolver el conjunto de resultados, todos los datos (y solo los datos) que se hayan confirmado en la base de datos a las 12:01:02.345 lo harán. en su conjunto de retorno. No se agregarán datos nuevos a su conjunto de declaraciones durante esos 5 minutos que le tomó a la base de datos procesar su estado de cuenta, ni se actualizará, y no se verán eliminaciones.

La arquitectura de Oracle logra la consistencia de lectura mediante la marca de tiempo interna de cada cambio en los datos y la creación de un conjunto de resultados a partir de dos fuentes: archivos de datos permanentes y un segmento de deshacer (o "segmento de reversión", como se conocía hasta la versión 10g).

Para soportarlo, la información de deshacer debe ser preservada. Si se sobrescribe, se produce el infame ORA-01555: snapshot too old .

Dejando de lado la administración de segmentos de deshacer, y cómo navegar por el error ORA-01555: snapshot too old , veamos las implicaciones de la consistencia de lectura en cualquier implementación práctica en Oracle. Además, ¿cómo debería reflejarse en SQL Server, que, como es el caso de otras implementaciones de RDBMS, con la excepción posible y calificada de PostgreSQL, no lo admite?

La clave es que las lecturas y escrituras de Oracle no se bloquean entre sí. También significa que es posible que su conjunto de retorno de consulta de ejecución prolongada no tenga los datos más recientes.

Las lecturas y escrituras sin bloqueo son una ventaja que tiene Oracle y afecta el alcance de las transacciones.

Pero la consistencia de lectura también significa que no tiene el estado más reciente de los datos. Cuando en algunos escenarios es perfectamente bueno (como producir un informe para un momento determinado), podría crear problemas importantes en otros.

No tener los datos más recientes, incluso "sucios" o no comprometidos, podría ser crítico: el escenario clásico es un sistema de reserva de habitaciones de hotel.

Considere el siguiente caso de uso: tiene dos agentes de servicio al cliente que aceptan simultáneamente pedidos de reserva de habitaciones. ¿Cómo puede asegurarse de que las habitaciones no se sobrevendan?

En SQL Server, puede iniciar una transacción explícita y SELECT un registro de la lista (que podría ser una tabla o una vista) de salas disponibles. Mientras esta transacción no se cierre (ya sea por COMMIT o ROLLBACK ), nadie puede obtener el mismo registro de habitación que ha seleccionado. Esto evita las reservas dobles, pero también hace que los demás agentes esperen entre sí para completar las solicitudes de reserva de una en una, de forma secuencial.

En Oracle, puede lograr el mismo resultado emitiendo una declaración SELECT ... FOR UPDATE contra registros que coincidan con sus criterios de búsqueda.

Nota: existen mejores soluciones, como establecer una bandera temporal que marque una habitación "en consideración" en lugar de bloquear ciegamente el acceso a ella. Pero esas son soluciones arquitectónicas, no opciones de idioma.

Conclusión : la consistencia de lectura de Oracle no es "totalmente buena" o "totalmente mala", sino una propiedad importante de la plataforma que debe entenderse bien y es fundamental para la migración de código entre plataformas.

Sinónimos públicos (y privados) en Oracle y Microsoft SQL Server

“Los sinónimos públicos son malvados”. No es exactamente mi descubrimiento personal, pero lo había aceptado como evangelio hasta que mi día, semana y año fueron guardados por sinónimos públicos.

En muchos entornos de bases de datos (diría que todos los entornos de Oracle con los que tuve la oportunidad de trabajar, pero ninguno que diseñé), usar CREATE PUBLIC SYNONYM para cada objeto era una rutina porque "siempre lo hemos hecho de esa manera".

En estos entornos, los sinónimos públicos tenían una sola función: permitir la referencia a un objeto sin especificar su propietario. Y esta es una razón mal pensada para hacer sinónimos públicos.

Sin embargo, los sinónimos públicos de Oracle pueden ser extremadamente útiles y brindar beneficios de productividad del equipo que superan significativamente todos sus inconvenientes, si se implementan y administran correctamente y con una razón. Sí, dije "productividad del equipo". ¿Pero cómo? Para esto, necesitamos entender cómo funciona la resolución de nombres en Oracle.

Cuando el analizador de Oracle encuentra un nombre (una palabra clave no reservada), intenta relacionarlo con un objeto de base de datos existente en el siguiente orden:

Un diagrama de flujo que comienza con my_object como entrada. ¿El esquema actual de la sesión emisora ​​tiene un objeto llamado my_object? Si es así, hemos terminado. Si no, ¿el esquema actual de la sesión emisora ​​tiene un sinónimo privado llamado my_object? Si es así, convertimos el sinónimo en un objeto y listo. Si no, ¿hay un sinónimo público llamado my_object? Si es así, resuélvelo y listo. Si no, busque un esquema con este nombre. Si encontramos uno, hemos terminado. Si no, genera un error.

Nota: El error generado será ORA-00942: table or view does not exist para declaraciones DML, o PLS-00201: identifier 'my_object' must be declared para procedimientos almacenados o llamadas a funciones.

En este orden de resolución de nombres, es fácil ver que cuando un desarrollador está trabajando en su propio esquema, cualquier objeto local con el mismo nombre que un sinónimo público ocultará este sinónimo público. (Nota: Oracle 18c implementó el tipo de esquema "solo inicio de sesión", y esta discusión no se aplica a él).

Sinónimos públicos para escalar equipos: control de cambios de Oracle

Veamos ahora un equipo hipotético de 100 desarrolladores que trabajan en la misma base de datos (que es algo que he experimentado). Además, supongamos que todos trabajan localmente en sus estaciones de trabajo personales y realizan compilaciones que no son de base de datos de forma independiente, todas vinculadas al mismo entorno de desarrollo de base de datos. La resolución de la fusión de código en código que no sea de base de datos (ya sea C#, Java, C++, Python o cualquier otro) se realizará en el momento del registro de control de cambios y entrará en vigencia con la siguiente compilación de código. Pero las tablas de la base de datos, el código y los datos deben cambiarse varias veces durante el desarrollo en curso. Cada desarrollador hace esto de forma independiente y surte efecto de inmediato.

Para ello, todos los objetos de la base de datos se crean en un esquema de aplicación común. Este es el esquema al que hace referencia la aplicación. Cada desarrollador:

  • Se conecta a la base de datos con su cuenta/esquema de usuario personal
  • Siempre comienza con un esquema personal vacío.
  • Hace referencia al esquema común solo a través de la resolución de nombres a un sinónimo público, como se describe anteriormente

Cuando un desarrollador necesita realizar cambios en la base de datos (crear o modificar una tabla, cambiar el código del procedimiento o incluso modificar un conjunto de datos para admitir algún escenario de prueba), crea una copia del objeto en su esquema personal. Lo hacen obteniendo el código DDL usando el comando DESCRIBE y ejecutándolo localmente.

A partir de este momento, el código de este desarrollador verá la versión local del objeto y los datos, que no será visible (ni tendrá impacto) para nadie más. Una vez que se completa el desarrollo, el código de la base de datos modificado se verifica en el control de código fuente y se resuelven los conflictos. Luego, el código final (y los datos, si es necesario) se implementa en el esquema común.

Después de esto, todo el equipo de desarrollo puede volver a ver la misma base de datos. El desarrollador que acaba de entregar el código elimina todos los objetos de su esquema personal y está listo para una nueva tarea.

Esta capacidad de facilitar el trabajo paralelo independiente para múltiples desarrolladores es el principal beneficio de los sinónimos públicos, una importancia que es difícil exagerar. Sin embargo, en la práctica, sigo viendo equipos que crean sinónimos públicos en las implementaciones de Oracle “simplemente porque siempre lo hacemos”. En cambio, en los equipos que usan SQL Server, no veo que la creación de sinónimos públicos se establezca como una práctica común. La funcionalidad existe pero no se usa con frecuencia.

En SQL Server, el esquema predeterminado actual para un usuario se define en la configuración del usuario y se puede cambiar en cualquier momento si tiene privilegios de "alterar usuario". Se puede implementar exactamente la misma metodología descrita anteriormente para Oracle. Sin embargo, si no se utiliza este método, no se deben copiar los sinónimos públicos.

Como Microsoft SQL Server no asocia una nueva cuenta de usuario con su propio esquema de forma predeterminada (como lo hace Oracle), la asociación debe ser parte de su script estándar de "creación de usuario".

A continuación se muestra un ejemplo de un script que crea esquemas de usuario dedicados y asigna uno a un usuario.

Primero, cree esquemas para los nuevos usuarios que deben incorporarse a la base de datos llamada DevelopmentDatabase (cada esquema debe crearse en su propio lote):

 use DevelopmentDatabase; GO CREATE SCHEMA Dev1; GO CREATE SCHEMA Dev2; GO

En segundo lugar, cree el primer usuario con su esquema predeterminado asignado:

 CREATE LOGIN DevLogin123 WITH PASSWORD = 'first_pass123'; CREATE USER Dev1 FOR LOGIN DevLogin123 WITH DEFAULT_SCHEMA = Dev1; GO

En este punto, el esquema predeterminado para el usuario Dev1 sería Dev1 .

A continuación, cree el otro usuario sin esquema predeterminado:

 CREATE LOGIN DevLogin321 WITH PASSWORD = 'second_pass321'; CREATE USER Dev2 FOR LOGIN DevLogin321; GO

El esquema predeterminado para el usuario Dev2 es dbo .

Ahora modifique el usuario Dev2 para cambiar su esquema predeterminado a Dev2 :

 ALTER USER Dev2 WITH DEFAULT_SCHEMA = Dev2; GO

Ahora, el esquema predeterminado para el usuario Dev2 es Dev2 .

Este script muestra dos formas de asignar y cambiar un esquema predeterminado para un usuario en las bases de datos de Microsoft SQL Server. Como SQL Server admite varios métodos de autenticación de usuarios (el más común es la autenticación de Windows) y los administradores del sistema pueden manejar la incorporación de usuarios en lugar de los DBA, el método ALTER USER para asignar/cambiar el esquema predeterminado será más útil.

Nota: hice que el nombre del esquema fuera el mismo que el nombre de un usuario. No tiene que ser así en SQL Server, pero es mi preferencia porque (1) coincide con la forma en que se hace en Oracle y (2) simplifica la administración de usuarios (abordando la mayor objeción por parte de un DBA para hacerlo bien en primer lugar): conoce el nombre de un usuario y automáticamente conoce el esquema predeterminado del usuario.

Conclusión : los sinónimos públicos son una herramienta importante para crear un entorno de desarrollo multiusuario estable y bien protegido. Desafortunadamente, en mi observación en la industria, se usa más a menudo por las razones equivocadas, dejando a los equipos sufriendo la confusión y otras desventajas de los sinónimos públicos sin darse cuenta de sus beneficios. Cambiar esta práctica para obtener beneficios reales de los sinónimos públicos puede generar beneficios reales para el flujo de trabajo de desarrollo de un equipo.

Gestión de acceso a bases de datos y procesos de gestión de cambios

Como acabamos de hablar sobre el soporte para el desarrollo paralelo por parte de grandes equipos, vale la pena abordar un tema separado y a menudo mal entendido: los procesos de control de cambios.

La gestión de cambios a menudo se convierte en una forma de trámites burocráticos controlados por los líderes de equipo y los DBA, despreciados por los desarrolladores rebeldes que quieren entregar todo, si no "ayer", sino "ahora".

Como DBA, siempre pongo barreras protectoras en el camino a "mi" base de datos. Y tengo una muy buena razón para ello: una base de datos es un recurso compartido.

Pío

En un contexto de control de código fuente, la gestión de cambios generalmente se acepta, ya que permite que un equipo vuelva de un código nuevo pero roto a un código antiguo pero funcional. Pero en el contexto de una base de datos, la gestión de cambios puede parecer un conjunto de barreras y restricciones irrazonables impuestas por los administradores de bases de datos: ¡es pura locura que ralentiza innecesariamente el desarrollo!

Dejemos a un lado la diatriba de este desarrollador: ¡Soy un DBA y no me tiraré piedras a mí mismo! Como DBA, siempre coloco barreras protectoras en el camino hacia "mi" base de datos. Y tengo una muy buena razón para ello: una base de datos es un recurso compartido.

Cada equipo de desarrollo, y cada uno de sus desarrolladores, tiene un objetivo definido muy específicamente y un resultado muy específico. El único objetivo que está en el escritorio de un DBA todos los días es la estabilidad de la base de datos como un recurso compartido. Un DBA tiene la función única en una organización de supervisar todos los esfuerzos de desarrollo en todos los equipos y controlar una base de datos a la que acceden todos los desarrolladores. Es el DBA quien se asegura de que todos los proyectos y todos los procesos se ejecuten sin interferir entre sí y que cada uno tenga los recursos necesarios para funcionar.

El problema es cuando tanto los equipos de desarrollo como los de DBA se sientan encerrados en sus respectivas torres de marfil.

Los desarrolladores no saben, no tienen acceso y ni siquiera les importa lo que sucede en la base de datos, siempre y cuando funcione bien para ellos. (No es su entregable, ni afectará su evaluación de desempeño).

El equipo de DBA mantiene la base de datos en secreto, protegiéndola de los desarrolladores que "no saben nada" al respecto, porque el objetivo de su equipo es la estabilidad de la base de datos. Y la mejor manera de garantizar la estabilidad es evitar cambios destructivos, lo que a menudo resulta en una actitud de proteger la base de datos de cualquier cambio tanto como sea posible.

Estas actitudes conflictivas hacia una base de datos pueden, como he visto, generar animosidad entre los equipos de desarrollo y DBA y dar como resultado un entorno inviable. Pero los DBA y el equipo de desarrollo deben trabajar juntos para lograr un objetivo común: brindar una solución comercial, que es lo que los unió en primer lugar.

Habiendo estado en ambos lados de la división desarrollador-DBA, sé que el problema es fácil de resolver cuando los DBA comprenden mejor las tareas y objetivos comunes de los equipos de desarrollo. Por su parte, los desarrolladores necesitan ver una base de datos no como un concepto abstracto sino como un recurso compartido, y allí, un DBA debe asumir el papel de un educador.

El error más común que cometen los DBA que no son desarrolladores es restringir el acceso de los desarrolladores al diccionario de datos y a las herramientas de optimización de código. El acceso a las vistas de catálogo Oracle DBA_ , las vistas dinámicas V$ y las tablas SYS les parece a muchos DBA como "privilegiado por DBA" cuando, de hecho, estas son herramientas de desarrollo críticas.

Lo mismo ocurre con SQL Server, con una complicación: el acceso a algunas vistas del sistema no se puede otorgar directamente, pero es solo una parte del rol de la base de datos SYSADMIN , y este rol nunca debe otorgarse fuera del equipo de DBA. Esto se puede resolver (y debería resolverse en el caso de la migración de un proyecto de Oracle a SQL Server) mediante la creación de vistas y procedimientos almacenados que se ejecuten con privilegios de SYSADMIN pero que sean accesibles para usuarios que no sean administradores de bases de datos. Este es el trabajo del DBA de desarrollo a medida que se configura un nuevo entorno de desarrollo de SQL Server.

La protección de datos es una de las principales responsabilidades de un DBA. A pesar de esto, es bastante común que los equipos de desarrollo tengan acceso total a los datos de producción sin filtrar para permitir la resolución de problemas de tickets relacionados con los datos. Estos son los mismos desarrolladores que tienen acceso limitado a la estructura de datos, estructura que ha sido creada por ellos o para ellos en primer lugar.

Cuando se establecen relaciones de trabajo adecuadas entre los equipos de desarrollo y DBA, la creación de un buen proceso de control de cambios se vuelve intuitiva. Los detalles y el desafío de la gestión de cambios del lado de la base de datos es la rigidez y la fluidez de una base de datos al mismo tiempo: la estructura es rígida, los datos son fluidos.

A menudo sucede que la gestión de cambios en la modificación de la estructura, es decir, en el lenguaje de definición de datos o DDL, está bien establecida, mientras que los cambios de datos tienen poco o nada en el camino de la gestión de cambios. La justificación es simple: los datos cambian todo el tiempo.

Pero si miramos esto más de cerca, veremos que en cualquier sistema, todos los datos caen en una de dos categorías: datos de aplicación y datos de usuario.

Los datos de la aplicación son un diccionario de datos que define el comportamiento de una aplicación y son tan críticos para sus procesos como cualquier código de aplicación. Los cambios en estos datos deben estar sujetos a estrictos procesos de control de cambios, al igual que con cualquier otro cambio de aplicación. Para crear transparencia en el proceso de control de cambios para los cambios de datos de la aplicación, los datos de la aplicación y los datos del usuario deben separarse explícitamente.

En Oracle, debe hacerse colocando los datos de la aplicación y del usuario en su propio esquema. En Microsoft SQL Server, debe hacerse colocando cada uno en un esquema separado o, mucho mejor, en una base de datos separada. Tomar estas decisiones debe ser parte de la planificación de la migración: Oracle tiene una resolución de nombres de dos niveles (esquema/propietario – nombre del objeto) mientras que SQL Server tiene una resolución de nombres de tres niveles (base de datos – esquema/propietario – nombre del objeto).

Una fuente común de confusión entre los mundos de Oracle y SQL Server son, quizás sorprendentemente, los términos base de datos y servidor :

Término del servidor SQL Término de Oracle Definición
servidor base de datos (usada indistintamente con servidor en el lenguaje común, a menos que se refiera específicamente al hardware del servidor, sistema operativo o elementos de red; puede haber una o más bases de datos en un servidor físico/virtual) Una instancia en ejecución que puede "hablar" con otras instancias a través de puertos de red
base de datos (parte de un servidor, contiene múltiples esquemas/propietarios) esquema/propietario La agrupación de más alto nivel

Esta confusión de terminología debe entenderse claramente en los proyectos de migración multiplataforma porque la mala interpretación de los términos puede dar lugar a decisiones de configuración incorrectas que son difíciles de abordar de forma retroactiva.

La separación correcta de los datos de la aplicación y del usuario permite que un equipo de DBA aborde su segunda preocupación más importante: la seguridad de los datos del usuario. Como los datos del usuario residen por separado, será muy sencillo implementar un procedimiento de ruptura de vidrio para acceder a los datos del usuario según sea necesario.

Conclusión : Los procesos de control de cambios son críticos en cualquier proyecto. En ingeniería de software, la gestión de cambios en el lado de la base de datos a menudo se descuida porque se considera que los datos son "demasiado fluidos". Pero es precisamente porque los datos son "fluidos" y "persistentes" al mismo tiempo que un proceso de control de cambios bien diseñado debe ser la piedra angular de una arquitectura de entorno de base de datos adecuada.

Sobre el uso de herramientas de migración de código

Las herramientas propias estándar, Oracle Migration Workbench y SQL Server Migration Assistant, pueden ser útiles en las migraciones de código. Pero lo que debe tenerse en cuenta es la regla 80/20: cuando el código se migre correctamente en un 80 %, resolver el 20 % restante requerirá el 80 % de su esfuerzo de migración.

El mayor riesgo en el uso de herramientas de migración es, con mucho, la percepción de "bala de plata". Uno puede tener la tentación de pensar: "Hará el trabajo, y solo tendré que hacer un poco de limpieza y orden". Observé un proyecto que fracasó debido a tal actitud del equipo de conversión y su liderazgo técnico.

Por otro lado, me tomó cuatro días hábiles realizar la conversión básica de un sistema Microsoft SQL Server 2008 de tamaño medio (alrededor de 200 objetos) utilizando la funcionalidad de reemplazo masivo de Notepad++ como la principal herramienta de edición.

Ninguno de los elementos críticos de migración que he abordado hasta ahora puede resolverse con herramientas de migración.

Claro, use las herramientas de asistencia para la migración, pero recuerde que solo brindan asistencia para la edición. El texto de salida resultante debe revisarse, modificarse y, en algunos casos, reescribirse para convertirse en un código digno de producción.

El desarrollo de herramientas de inteligencia artificial puede abordar estas deficiencias de las herramientas de migración en el futuro, pero espero que las diferencias entre las bases de datos desaparezcan antes de esa fecha y que cualquier proceso de migración en sí sea innecesario. Entonces, mientras se necesiten este tipo de proyectos, tendremos que hacerlo a la antigua usanza, utilizando la inteligencia humana a la antigua.

Conclusión : el uso de herramientas de asistencia para la migración es útil, pero no es una solución mágica, y cualquier proyecto de conversión aún requiere una revisión detallada de los puntos anteriores.

Migraciones de Oracle/SQL Server: siempre eche un vistazo más de cerca

Oracle y Microsoft SQL Server son las dos plataformas RDBMS más proliferadas en el entorno empresarial. Ambos tienen un cumplimiento básico con el estándar ANSI SQL y se pueden mover pequeños segmentos de código con muy pocas modificaciones, o incluso tal cual.

Esta similitud crea una impresión engañosa de que la migración a través de las dos plataformas es una tarea simple y directa y que la misma aplicación se puede adoptar fácilmente usando un back-end RDBMS a otro.

En la práctica, tales migraciones de plataforma están lejos de ser triviales y deben tener en cuenta los elementos finos del funcionamiento interno de cada plataforma y, sobre todo, la forma en que implementan el soporte para el elemento más crítico de la gestión de datos: las transacciones.

Si bien cubrí dos plataformas RDBMS que son el núcleo de mi experiencia, la misma advertencia, "se parece no significa que funciona de la misma manera", se debe aplicar al mover código entre cualquier otro sistema de administración de bases de datos compatible con SQL. Y en todos los casos, el primer punto de atención debe ser cómo la implementación de la gestión de transacciones difiere entre las plataformas de origen y de destino.