Ese asunto de los cursores

Introducción

La idea básica de este post es avanzar un poco más en el análisis de las razones  por las cuales es recomendable evitar el uso de cursores.

Razones principales del impacto de los cursores server-side en los recursos del Database Engine

El Database Engine esta optimizado para procesar conjuntos de registros, de la misma forma que el lenguaje T-SQL es un lenguaje de tipo imperativo orientado a conjuntos de registros, donde los comandos indican el resultado a obtener en vez de detallar el camino para obtenerlo. En suma, tanto el Engine como T-SQL están diseñados de acuerdo con un esquema set-oriented.

Los cursores son un recurso programático que permite recuperar en memoria un conjunto de registros y procesarlos un registro por vez, es decir, operan con un esquema de tipo record-oriented.

En el caso de cursores implementados en T-SQL, para que el Database Engine pueda lograr que este tipo de recursos opere en forma adecuada y lo haga en armonía con el resto de sí mismo, necesita contener a los cursores en un entorno de ejecución propio, adecuado para el esquema record-oriented, que permita conservar la consistencia y armonía entre el cursor y el resto de las cosas que el Engine controla, que operan con el modelo set-oriented.

Dicho entorno de ejecución consume en forma significativa recursos compartidos y escasos, y esta es la razón principal por lo cual es tan generalizada la recomendación de evitar el uso de cursores, en particular, cursores server-side, tal como es el caso de los cursores implementados en T-SQL.

Por su parte, en el caso de los cursores server-side, la metadata del cursor, necesaria para su ejecución, es almacenada en memoria del mismo server, lo que agrava aún más la situación en relación al consumo de recursos compartidos y escasos de la instancia.

Otros problemas asociados al uso de cursores

Además de los problemas ya mencionados en relación al uso de cursores en T-SQL, es común que surjan algunos otros problemas que afectan al uso de recursos en una instancia durante la ejecución de una rutina basada en cursores T-SQL.

Estos problemas frecuentes son consecuencia del hecho que no se configura el cursor en forma adecuada según los requerimientos de la rutina que lo contiene.

Para ilustrar este tipo de problemas, usaremos como base de nuestro análisis un ejemplo típico de uso de cursores que podemos obtener haciendo una búsqueda en Internet.

Un ejemplo “clásico” podria ser algo así:

DECLARE @name VARCHAR(50) — database name

DECLARE @path VARCHAR(256) — path for backup files

DECLARE @fileName VARCHAR(256) — filename for backup

DECLARE @fileDate VARCHAR(20) — used for file name

SET @path = ‘C:\Backup\’

SELECT @fileDate = CONVERT(VARCHAR(20),GETDATE(),112)

DECLARE db_cursor CURSOR FOR

SELECT name

FROM MASTER.dbo.sysdatabases

WHERE name NOT IN (‘master’,’model’,’msdb’,’tempdb’)

OPEN db_cursor

FETCH NEXT FROM db_cursor INTO @name

WHILE @@FETCH_STATUS = 0

BEGIN

SET @fileName = @path + @name + ‘_’ + @fileDate + ‘.BAK’

BACKUP DATABASE @name TO DISK = @fileName

FETCH NEXT FROM db_cursor INTO @name

END

CLOSE db_cursor

DEALLOCATE db_cursor

Vamos a usar para el análisis un ejemplo de cursores similar, con el mismo tipo de configuración de cursor no adecuada.

Vamos a usar la base de datos AventureWorks para este ejemplo (en realidad, una copia de la misma cuyo nombre es AW).

A fin de mostrar como afecta el uso de una configuración no adecuada del cursor, el ejemplo de código no cierra el cursor, es decir, lo deja abierto para ver que pasa con la base de datos afectada por un cursor con este tipo de configuración durante la ejecución del mismo.

El código de la rutina de ejemplo es el siguiente:

DECLARE @OrderQty int

DECLARE @QtyIncrease decimal(8, 3)

USE AW

DECLARE db_cursor CURSOR FOR

SELECT OrderQty from Sales_SalesOrderDetail order by SalesOrderDetailId

OPEN db_cursor

FETCH NEXT FROM db_cursor INTO @OrderQty

BEGIN

SET @QtyIncrease = (@OrderQty * 1.25)

PRINT @QtyIncrease

FETCH NEXT FROM db_cursor INTO @OrderQty

END

Para analizar como un cursor con esta configuración afecta a la base de datos y a la instancia involucradas en su ejecución, usaremos el siguiente query con algunas DMVs adecuadas para el análisis de ejecución de cursores:

SELECT c.creation_time, c.cursor_id, c.name, c.session_id

,tl.resource_type

,tl.resource_description

,tl.request_session_id

,tl.request_mode

,tl.request_type

,tl.request_status

,tl.request_reference_count

,tl.request_lifetime

,tl.request_owner_type

,s.transaction_isolation_level

,s.login_time

,s.last_request_start_time

,s.last_request_end_time

,s.status

,s.program_name

,s.nt_user_name

FROM sys.dm_exec_cursors(0) AS c

inner JOIN sys.dm_exec_sessions AS s ON c.session_id = s.session_id

inner join sys.dm_tran_locks tl on

tl.request_session_id = s.session_id

GO

El resultado de este query es algo así:

 Result

Como se puede apreciar, durante la ejecución de un cursor con este tipo de configuración, el cursor aplica un lock a la base de datos que contiene a las tablas involucradas.

Dado que a propósito no hemos cerrado el cursor, podemos verificar el lock de la base de datos completa intentando hacer algún cambio a la misma que ponga de manifiesto dicho lock, como por ejemplo, intentar renombrarla.

Al intentar renombrar a la base de datos AW, despues de unos segundos SSMS retorna el siguiente mensaje de error:

Error_Message

La falta de la correcta configuración de los cursores server-side es un error muy común y generalizado.

Sin embargo, en este post no le dedicaremos tiempo a revisar los detalles de una correcta configuración de cursores server-side, dado que el objetivo principal del post es exponer las razones por las cuales no deberíamos usar cursores, y si hemos puesto el foco en exponer con ejemplos concretos algunas de las consecuencias negativas que explican porque no deberíamos usar cursores.

Saludos, GEN

XAML y el desarrollo cross-platform de la UI de smartphone apps

Blue Wave

En este post revisaremos brevemente algunas de las razones por las cuales el uso de XAML en el desarrollo cross-platform de la UI de smartphone apps es una decisión de diseño muy importante, lo que habla muy bien de aquellas empresas, como Xamarin, que han tomado tal decisión.

Contexto de hardware gráfico previo al lanzamiento de Windows Vista

Previo al lanzamiento de Windows Vista, un porcentaje de las PCs de ese entonces contaban con hardware acelerador de gráficos, tales como tarjetas aceleradoras dedicadas, en el caso de usuarios asiduos de los video games de PCs, o chipsets con capacidades básicas de aceleración integradas en el motherboard.

Previo al lanzamiento de Vista, para poder trabajar con dicho hardware gráfico especializado, el software debía hacer uso de APIs complejos como Direct3D, mientras que la funcionalidad gráfica básica de Windows se basa en el uso de otros APIs más sencillos pero con capacidades más básicas, como es el caso de GDI+.

En base a este panorama, la gente de Microsoft vió propicio incorporar a las tools de desarrollo de .NET, a través de nuevos componentes del framework, un nuevo API integrador de manejo gráfico que evitase la complejidad para los desarrolladores de tener que lidiar con diversos APIs, de acuerdo con el hardware con el que disponga la PC en cuestión.

Este nuevo API integrador es Windows Presentation Foundation, que detecta que hardware gráfico está disponible en la PC y lo aprovecha para obtener el mejor resultado visual posible, como por ejemplo, aplicaciones cuya interfase de usuario presente ventanas con algún porcentaje de transparencia.

Esto puede parecer algo superfluo, pero la presión competitiva de las interfases de usuario con efectos visuales atractivos que ofrecían las aplicaciones en Mac era muy fuerte y llevó a Microsoft a pensar como incorporar al desarrollo .NET un API con una curva de aprendizaje relativamente baja (en comparación con la necesaria para aprender a usar Direct3D) que permita que muchos desarrolladores puedan implementar rapidamente aplicaciones visualmente muy atractivas.

Breve revisión de la arquitectura de Windows Presentation Foundation

Para poder comprender el aporte crucial que representa usar XAML en el desarrollo cross-platform de la Interfase de Usuario (UI) de smartphone apps, es conveniente revisar brevemente la arquitectura de Windows Presentation Foundation, que es el área del framework de .NET donde se usa XAML vinculado con el desarrollo de la interfase de usuario de una aplicación.

WPF Arch

WPF Architecture

Como se puede apreciar, un único y mismo API que permite describir los elementos de interfase de usuario en WPF puede usar el hardware gráfico disponible, a fin de aplicar los efectos visuales solicitados con la mejor performance que el equipo permita.

Es importante destacar el punto mas relevante del diagrama de arquitectura: el mismo API de elementos de interfase de usuario puede ser ejecutado por hardware diverso, en base a lo que este disponible en el equipo en cuestión, y es el mismo framework el que aisla al programador de la decisión de que clases dentro del árbol de herencia es necesario invocar para tener acceso al hardware a usar.

Ventajas de XAML/WPF para el desarrollo Cross-Platform de Smartphone Apps

Dadas las características de WPF mencionadas previamente, empresas como Xamarin vieron las ventajas implícitas en la arquitectura original de WPF para extenderla, de tal forma de ser aprovechada para el desarrollo cross-platform de smartphone apps de diversos vendors, que han de ejecutar en forma nativa en diferentes sistemas operativos y con diferente hardware.

La amplia experiencia previa de la gente de Mono (nucleo de desarrollo del que se derivó el equipo de desarrollo de Xamarin) en la extensión del framework de .NET y de la implementación del CLR para otros sistemas operativos y plataformas de hardware les ha permitido realizar este tipo de adaptaciones en forma exitosa y ofrecer estas ventajas a los desarrolladores.

Saludos, GEN

Escalabilidad Infinita y tablas Memory-Optimized

Clock

 

 

En este post voy a analizar algunos escenarios de escalabilidad de aplicaciones, en particular, aquellos escenarios que pueden verse beneficiados con el uso de tablas memory-optimized.

Los puntos principales del post son los siguientes:

  • Rangos de escalabilidad de aplicaciones
  • Algunas restricciones a la escalabilidad infinita impuestas por la arquitectura tradicional de base de datos relacionales
  • Ventajas de las tablas memory-optimized para sistemas con escalabilidad infinita

Rangos de escalabilidad de aplicaciones

Cuando hablamos de escalabilidad de aplicaciones, nos referimos a la capacidad que tiene una aplicación dada de mantener el mismo nivel de performance ante cantidades crecientes de usuarios concurrentes que la utilizan.

La escalabilidad de aplicaciones puede agruparse en diversos rangos, según el punto de vista del análisis, pero una forma típica es la siguiente:

  • Escalabilidad básica
  • Escalabilidad intermedia
  • Escalabilidad ilimitada o infinita

Escalabilidad básica es el rango mínimo de escalabilidad, que abarca entre uno y unos pocos miles de usuarios concurrentes.

En este rango se ubican aplicaciones de PyMEs y aplicaciones departamentales de grandes empresas.

La edición Express de SQL Server puede atender este rango de escalabilidad.

Este rango no es el foco de este post.

Escalabilidad Intermedia es un rango que abarca entre unos pocos miles y varias decenas de miles a varios cientos de miles (para muchos escenarios) de usuarios concurrentes. Este es el rango de escalabilidad que las ediciones de SQL Server a partir de la Standard pueden proveer (con los recursos apropiados de hardware del server).

En este rango se ubican aplicaciones corporativas del estilo de ERP, portales corporativos, aplicaciones de Helpdesk y otras similares.

En este rango de escalabilidad, las ediciones de SQL Server mencionadas (con los recursos de hardware apropiados), son capaces de atender con alta performance a todo tipo de escenarios. También es importante destacar que a partir de este rango de escalabilidad, es imprescindible usar versiones 64 bits de SQL Server con múltiples procesadores de múltiples núcleos, y con un dimensionamiento adecuado de memoria.

Escalabilidad ilimitada o infinita es el rango que se corresponde con aplicaciones web de uso masivo, a partir de varias decenas de miles de usuarios concurrentes en adelante, sin cota superior definida.

Este rango puede ser atendido por las mismas ediciones ya mencionadas de SQL Server, con los adecuados recursos de hardware en el server, sin embargo, es importante destacar que con cantidades muy grandes de usuarios concurrentes, existen diversos escenarios donde puede aumentar la latencia en las transacciones hasta niveles no deseables: este es el tipo de escenarios que se puede beneficiar con las ventajas de las tablas memory-optimized.

Para poder analizar las ventajas que las tablas memory-optimized ofrecen para este tipo de requerimiento (escalabilidad infinita), es necesario analizar con más detalle algunas de las restricciones a la escalabilidad infinita que imponen algunos elementos de la arquitectura tradicional de los engines de bases de datos relacionales.

Algunas restricciones a la escalabilidad infinita impuestas por la arquitectura tradicional de base de datos relacionales

Vamos a repasar brevemente la secuencia de pasos que ocurren en un server de base de datos SQL Server desde que recibe una solicitud de ejecutar un proceso hasta que el resultado del proceso es retornado al proceso cliente en un contexto de escalabilidad infinita.

Para realizar este breve análisis, me focalizaré en un concepto que es útil para este propósito: el concepto de recurso limitante.

En un contexto de alta escalabilidad, el server de base de datos ha de recibir una cantidad muy alta de Remote Procedure Calls concurrentes, provenientes de procesos cliente.

Para poder atender a todos estas invocaciones concurrentes sin tener que encolarlas, es necesario que el server tenga multiples procesadores con múltiples núcleos.

Desde este punto de vista, el procesamiento paralelo es favorable para cubrir el requerimiento de escalabilidad infinita.

Para poder ejecutar el proceso solicitado, el server ha de verificar si los datos necesarios para dicho proceso están disponibles en el Data Caché.

Este es el primer recurso limitante relevante que se presenta en los diversos pasos a seguir para ejecutar el proceso solicitado.

Si en el Buffer Pool no están todos los datos necesarios, el server debe leer los datos faltantes en los files que los contienen y ubicarlos en el Data Caché para poder ejecutar el proceso solicitado.

Al querer leer los datos faltantes en los files que los contienen, aparece el segundo recurso limitante relevante: que el disco que contiene los files donde se alojan los datos requeridos esté ocupado realizando otra tarea previa.

Esto hace que se debe encolar la tarea de lectura y esperar su turno hasta que pueda ser realizada: esta espera es la causante de los wait types “infames” del tipo PageIOLatch*.

Es importante destacar que tener múltiples procesadores no ayuda para reducir ambos recursos limitantes: es más, cuantos más procesadores tenga el server, es más probable que múltiples invocaciones concurrentes estén “peleando” entre sí por los recursos limitantes mencionados.

También es importante destacar que el aumento de memoria permite tener un Data Caché más grande, y por lo tanto, bajar un poco la probabilidad que el server no encuentre los datos necesarios para ejecutar el proceso solicitado y por lo tanto, tenga que leer dichos datos de los files que los contienen.

En cuanto al recurso limitante que el disco esté ocupado con otra tarea previa, el elemento crucial es la velocidad del disco, y tener más procesadores o más memoria en el server no resuelve  en forma significativa este problema (toda vez que es necesario ir a leer los datos faltantes).

En resumen, las restricciones a la escalabilidad infinita surgen por el tiempo total necesario para ejecutar el proceso solicitado, y dicho tiempo se ve afectado por la espera para leer los datos faltantes, y esto ocurre porque dichos datos no están disponibles en el Data Caché al momento de ejecutar el proceso solicitado.

Por lo tanto, si se puede garantizar que los datos necesarios para un proceso en particular estén “siempre” en memoria, se eliminan las restricciones mencionadas a la escalabilidad infinita.

Justamente, esto es lo que aporta el uso de tablas memory-optimized a los escenarios de escalabilidad infinita.

Ventajas de las tablas memory-optimized para sistemas con escalabilidad infinita

Al eliminar la necesidad de tener que ir a leer al disco los datos faltantes para ejecutar un proceso en particular, el uso de tablas memory-optimized puede mejorar en forma significativa la performance de los procesos que operan con dichas tablas, donde el factor de mejora típicamente es por lo menos un orden de magnitud, y en muchos casos, dos órdenes de magnitud: justamente esto justificó que el codename de esta tecnología sea Hekaton, que literalmente es “cien” en griego.

Este nivel de mejora de performance es crucial para aplicaciones tanto Internet Facing como Cloud.

Para aplicaciones Web Internet Facing, se tiene disponible las tablas memory-optimized en SQL Server 2014 Enterprise (On Premises), mientras que para Cloud-based web applications, se tiene disponible tablas memory-optimized en SQL Azure.

Saludos, GEN

 

¿ Qué es un objeto Sequence y en que escenarios se usa ?

En este post voy a tratar brevemente sobre que es un objeto de base de datos Sequence, y en que escenarios se usa.

Focalizaremos nuestra atención en este post en analizar el uso básico de Sequence, las comparaciones principales entre Identity y Sequence, y las principales razones de requerimientos funcionales que justifican el uso de objetos Sequence, pero tratar en otro post el análisis de razones técnicas para optar por el uso de Identity o de Sequence en determinados tipos de escenarios.

Los puntos principales de este post son los siguientes:

  • ¿ Qué es un objeto de base de datos Sequence ?
  • ¿ Qué similitudes y diferencias existen entre Sequence y Identity ?
  • Escenarios típicos donde se usa Sequence

¿ Qué es un objeto de base de datos Sequence ?

Un Sequence es un objeto de base de datos que permite recuperar el próximo valor numérico entero de una secuencia de números, configurada con un valor mínimo, un valor máximo, un valor inicial y un valor de paso o incremento.

Un objeto Sequence posee algunos elementos parecidos a un Identity, pero a diferencia de este último, el Sequence es un objeto de base de datos independiente de una tabla, mientras que un Identity es una propiedad de un campo de una tabla.

Es importante no confundir Sequence con Identity, por lo tanto, es conveniente que revisemos la sintaxis de la sentencia de creación de un Sequence a través de algunos ejemplos.

Antes de entrar de lleno a los ejemplos, es necesario destacar que la secuencia de valores de un objeto Sequence es un conjunto de números que define el dominio de dicho objeto, donde el dominio es el conjunto de valores válidos.

Dado que la operación básica con un objeto Sequence es la de recuperación del próximo valor en la secuencia, debemos tomar aquellas decisiones de diseño que nos aseguren que la lógica de la solución que opera con un objeto Sequence (en base a solicitar el próximo valor de la secuencia), lo haga a sabiendas que el próximo valor a recuperar pertenece al dominio del objeto Sequence a invocar, porque de lo contrario, el objeto Sequence arrojará una exception por haber solicitado un próximo valor cuando el dominio del mismo ya está agotado.

La sintaxis mínima de creación de un objeto Sequence es así:

CREATE SEQUENCE UnTurno;

GO

Esta sentencia no indica ningún valor numérico (ni un valor inicial, ni un valor mínimo, ni un valor máximo, ni un valor de paso o incremento), por lo tanto, el engine aplica los defaults de la sentencia para ejecutar el comando.

En este caso, los defaults aplicados son los siguientes:

El tipo de dato asignado al Sequence creado (dado que el comando usado no define un tipo de dato en particular para el objeto Sequence) es bigint.

El paso o incremento asignado al Sequence creado (dado que el comando no define paso o incremento) es +1, es decir, por defecto, es un Sequence ascendente de incremento unitario.

En este caso, tanto el valor mínimo como el valor inicial asignado al Sequence creado (dado que el comando no define ninguno de los dos) se corresponden con el valor mínimo del data type para un Sequence ascendente, o el valor máximo del data type para un Sequence descendente. En este caso, como el data type es bigint y el Sequence es ascendente por defecto, el valor mínimo y el valor inicial de este Sequence es el valor mínimo del data type bigint, es decir, el valor inicial es el número entero -9.223.372.036.854.775.808.

El valor máximo asignado al Sequence creado (dado que el comando no define un valor inicial) es el valor máximo del data type para un Sequence ascendente, o el valor mínimo del data type para un Sequence descendente. En este caso, como el data type es bigint y el Sequence es ascendente por defecto, el valor máximo de este Sequence es el valor máximo del data type bigint, es decir, el valor máximo es el número entero 9.223.372.036.854.775.807.

En este caso de comando mínimo que opera con todos los defaults, Sequence no usa Caché de números de la secuencia, ni recicla cuando llega al final de la secuencia: en aquellos casos como este, donde los límites de la secuencia (valores inicial y final) coinciden con los límites del data type asociado a dicha sequencia, el Sequence no puede reciclar.

Ya mencionamos al inicio del post que nos focalizaremos en las razones de uso del Sequences basadas en requerimientos funcionales y dejaremos para otro post el análisis de razones técnicas, por lo tanto, en estos ejercicios veremos el uso de Sequence con reciclado de dominio, pero no veremos el uso de Sequence con Caché, dado que los pros y contras de usar Sequence con Caché son principalmente técnicas y de Quality Attributes.

Tal como es esperable, contamos con una System View, sys.sequences, para consultar sobre la metadata y el estado actual de cada objeto Sequence de una base de datos dada:

SELECT * FROM sys.sequences WHERE name = N’UnTurno';

Al revisar los detalles del Sequence creado en esta System View, podemos verificar que indica que tanto el valor inicial del mismo es el número -9.223.372.036.854.775.808, y el valor mínimo es también dicho número. De igual forma, podemos revisar el resto de los datos de metadata (valor máximo, incremento, valor actual del Sequence) del Sequence recién creado.

Para que un Sequence sea realmente útil, tenemos que ver que comando usar para recuperar el próximo valor de dicha secuencia:

SELECT NEXT VALUE FOR UnTurno;

Vemos que el valor que retorna este comando para el Sequence recién creado se corresponde con el valor inicial, es decir, en este caso retorna el valor -9.223.372.036.854.775.808.

Queda claro que si al crear un objeto Sequence no le definimos en forma explícita que pertenece a un Schema existente dado, por defecto pertenece al Schema dbo.

Veamos ahora un ejemplo algo más completo, donde definimos en forma explícita el data type, valor inicial, y paso o incremento del Sequence (usamos el data model OLTP de AdventureWorks para SQL Server 2012 en los ejemplos restantes):

USE AdventureWorks2012

GO

IF EXISTS (SELECT * FROM sys.sequences WHERE name = N’UnTurno’)

     DROP SEQUENCE UnTurno;

GO

CREATE SEQUENCE UnTurno AS tinyint

     START WITH 0

     INCREMENT BY 100;

GO

— Cuarto Select ha de fallar

SELECT NEXT VALUE FOR UnTurno;

SELECT NEXT VALUE FOR UnTurno;

SELECT NEXT VALUE FOR UnTurno;

SELECT NEXT VALUE FOR UnTurno; — <= Falla!

Era predecible que la cuarta invocación del “NEXT VALUE FOR” debe arrojar una exception, dado que queda fuera del rango válido de valores (fuera del dominio) que pertenecen a la secuencia configurada en el Sequence creado en este ejercicio.

En relación con los data types que se pueden usar para definir en un Sequence, podemos usar todos los data types de tipo entero built-in que soporta SQL Server, así como todos aquellos alias data types que hemos creado que referencian a cualquiera de los data types enteros built-in (un ejemplo con el uso de Sequence con alias data type es un caso de razón principalmente técnica, y no lo veremos en este post).

A continuación veremos cómo crear un objeto Sequence capaz de retornar valores de una secuencia periódica, y en este caso, definimos en forma explícita tanto el data type, como el valor inicial, el valor mínimo, el valor máximo y el paso o incremento. Para lograr esto, vamos a ver un caso con reciclado.

USE AdventureWorks2012

GO

IF EXISTS (SELECT * FROM sys.sequences WHERE name = N’UnTurno’)

     DROP SEQUENCE UnTurno;

GO

CREATE SEQUENCE UnTurno AS tinyint

     START WITH 0

     INCREMENT BY 1

     MINVALUE 0

     MAXVALUE 3

     CYCLE;

GO

— Estos selects no presentan falla

SELECT NEXT VALUE FOR UnTurno;

SELECT NEXT VALUE FOR UnTurno;

SELECT NEXT VALUE FOR UnTurno;

SELECT NEXT VALUE FOR UnTurno;

SELECT NEXT VALUE FOR UnTurno;

SELECT NEXT VALUE FOR UnTurno;

SELECT NEXT VALUE FOR UnTurno;

SELECT NEXT VALUE FOR UnTurno;

SELECT NEXT VALUE FOR UnTurno;

SELECT NEXT VALUE FOR UnTurno;

Al ejecutar todos estos “NEXT VALUE FOR”, se aprecia claramente el comportamiento periódico o cíclico de la secuencia configurada en el Sequence creado en este ejercicio, y como los parámetros de configuración del mismo determinan dicho comportamiento y el rango de valores del dominio de dicho período.

¿ Qué similitudes y diferencias existen entre Sequence y Identity?

Tal como hemos visto al comienzo de este post, la principal diferencia entre un objeto Sequence y Identity, es que el objeto Sequence es un objeto independiente, mientras que un Identity es una propiedad de una columna de una tabla.

Otras diferencias importantes entre Sequence y Identity es que un objeto Sequence solamente puede retornar valores numéricos de data types enteros, mientras que una columna con propiedad Identity puede estar asociada tanto a data types enteros como a data types con decimales: las columnas Identity solo pueden tener valores enteros, pero el uso de data types como el decimal(x,y) permite tener un rango de valores válidos más amplio que con la mayoría de los data types enteros (el soporte de decimal(18,0) en columas Identity tenía sentido antes de la inclusión del data type bigint).

Una diferencia a destacar es que Sequence permite crear secuencias periódicas de valores numéricos, mientras que Identity solamente puede crear secuencias no periódicas.

Otra diferencia relevante es que Sequence se puede usar en muchos contextos, como por ejemplo, para asignar en forma directa un valor a una variable, formando parte de una expresión en SELECTs, INSERTs o UPDATEs, mientras que un Identity solamente puede asignarle valor a la columna asociada en INSERTs.

En cuanto a las similitudes, ambos permiten crear secuencias de números con un valor inicial, un valor máximo, un valor de paso o incremento, tanto secuencias ascendentes como descendentes.

Un ejemplo sencillo de uso de Sequence con INSERTs y UPDATEs es el siguiente:

USE AdventureWorks2012

GO

IF EXISTS (SELECT * FROM sys.sequences WHERE name = N’UnTurno’)

     DROP SEQUENCE UnTurno;

GO

CREATE SEQUENCE UnTurno AS tinyint

     START WITH 0

     INCREMENT BY 1

     MINVALUE 0

     MAXVALUE 3

     CYCLE;

GO

CREATE TABLE data1

(col1 int not null);

GO

INSERT data1

VALUES (NEXT VALUE FOR UnTurno);

GO 10

UPDATE data1

SET col1 = NEXT VALUE FOR UnTurno;

SELECT col1 from data1;

Escenarios típicos donde se usa Sequence

Vamos a concentrar nuestra atención en algunos ejemplos de requerimientos funcionales que son adecuadamente implementados a través de objetos Sequence.

Por ejemplo, el tipo de requerimiento funcional que claramente se implementa en forma adecuada mediante objetos Sequence es el manejo de turnos por orden de llegada.

En diversos lugares de atención al público o a clientes, como en oficinas públicas o en bancos, es común que el esquema de atención al público es por estricto orden de llegada de los clientes. En forma tradicional, para administrar este manejo y evitar problemas con los clientes, se usan talonarios con tickets pre-impresos con una secuencia de números.

Más recientemente, las organizaciones han mostrado interés en implementar sistemas que emitan los tickets en forma automática, por lo tanto, es conveniente contar con mecanismos robustos que permitan generar secuencias configurables de números similares a las existentes en los talonarios de números.

Es conveniente presentar un caso concreto para apreciar cuan conveniente es usar un Sequence como base de la implementación de un requerimiento funcional de este tipo. Supongamos que tenemos que implementar una solución que sea capaz de generar turnos por orden de llegada en base a tickets numerados secuenciales cíclicos, con una secuencia de números entre 1 y 100, periódica o cíclica, que después del 100 recicle al número 1 y repita la secuencia.

A nivel de la capa de acceso a datos (SQL Server), la implementación tendrá un aspecto similar al siguiente:

USE AdventureWorks2012

GO

IF EXISTS (SELECT * FROM sys.sequences WHERE name = N’UnTurno’)

     DROP SEQUENCE UnTurno;

GO

CREATE SEQUENCE UnTurno AS tinyint

     START WITH 1

     INCREMENT BY 1

     MINVALUE 1

     MAXVALUE 100

     CYCLE;

GO

— Estos selects permiten probar la implementación

SELECT NEXT VALUE FOR UnTurno;

GO 98;

SELECT NEXT VALUE FOR UnTurno;

SELECT NEXT VALUE FOR UnTurno;

SELECT NEXT VALUE FOR UnTurno;

Los SELECTs permiten ver como el Sequence ejecuta el reciclado y vuelve a repetir la secuencia de números del dominio en forma periódica, de tal forma que permite operar de igual forma que con un talonario de tickets pre-impreso que cuando se termina un talonario (con el Nro 100), se empieza a usar un nuevo talonario desde el comienzo, es decir, a partir del primer ticket que aparece, con el Nro 1.

 Con esto concluimos esta presentación introductoria del objeto de base de datos Sequence, donde se han expuesto ejemplos de escenarios funcionales que justifican su uso.

Saludos, GEN

 

Cómo integrar los requerimientos de DBAs y Admins a las decisiones de diseño de una solución

En este post voy a tratar brevemente sobre qué podemos hacer para asegurarnos que los requerimientos de DBAs y Admins están adecuadamente cubiertos por las decisiones de diseño de una solución, en equilibrio con una adecuada cobertura de los requerimientos de los demás stakeholders de dicha solución.

Los puntos principales de este post son los siguientes:

  • Los DBAs y Admins también son stakeholders de primer nivel de una solución
  • Los requerimientos de DBAs y Admins suelen “asomar” a través de los requerimientos no funcionales de la solución
  • Pensar en cómo automatizar el deployment de la solución desde el comienzo
  • Incorporar metodologías como DevOps para mejorar la integración con DBAs y Admins en los deployments

Los DBAs y Admins también son stakeholders de primer nivel de una solución

Un problema frecuente que se presenta en la documentación de requerimientos es que resulta poco probable que los usuarios clave entrevistados por los analistas funcionales tengan presentes los requerimientos de los DBAs y de los Admins y los describan con suficiente detalle.

En suma, los requerimientos de los DBAs y Admins pasan a engrosar la lista de los requerimientos “invisibles” de la solución en cuestión: son todos aquellos requerimientos que no tienen un “vocero” que los saque del anonimato, a tiempo.

Lamentablemente, este es un hecho muy frecuente, y un abrumador porcentaje de las soluciones existentes tiene su lista de requerimientos “invisibles”, que típicamente incluye a los requerimientos de los DBAs y Admins.

Un elemento que contribuye a que los requerimientos de los DBAs y Admins sean “invisibles” es que la gran mayoría de los usuarios no comprende de qué forma puede comprometer seriamente la correcta operación de la solución si los requerimientos de los DBAs y Admins no están adecuadamente cubiertos.

Qué podríamos hacer para mejorar esto ?

Existe una alternativa de resolución muy simple: que el arquitecto sea el que “saque del anonimato” a los requerimientos de DBAs y Admins, junto con otros requerimientos “invisibles” importantes.

Una forma apropiada para hacer esto es que el arquitecto le sugiera a los analistas funcionales como orientar las preguntas de requerimientos en general, y en particular, sobre los no funcionales.

Los requerimientos de DBAs y Admins suelen “asomar” a través de los requerimientos no funcionales de la solución

Ciertamente, los requerimientos de los DBAs y los Admins no son “completamente invisibles”, más bien, son altamente “transparentes”, ya que estos requerimientos suelen “asomar” en forma velada o indirecta a través de los requerimientos no funcionales que los usuarios normalmente describen.

Por diversas razones, tanto prácticas como técnicas, los arquitectos preferimos agrupar los requerimientos de una solución en categorías que se denominan Quality Attributes.

Consideremos brevemente algunos Quality Attributes (QAs) relevantes que suelen “hacer visibles” a algunos de los requerimientos de DBAs y Admins:

  • Performance
  • Escalabilidad
  • Seguridad
  • Alta Disponibilidad/Disaster Recovery (HA/DR)
  • Mantenibilidad
  • Administrabilidad

Veamos un ejemplo sobre como algunos requerimientos de seguridad pueden “hacer visibles” a requerimientos importantes de DBAs, Admins y otras áreas.

Supongamos que un documento de requerimientos de una solución dice algo similar a lo siguiente:

“Esta solución Web debe ser Internet Facing, dado que debe soportar tanto a usuarios de Intranet como a usuarios de Extranet”

Esta sola frase remite a requerimientos de los DBAs, de los Admins y de Seguridad Informática.

Repasemos brevemente las implicancias que esta frase tiene en las decisiones de diseño para que la solución cubra adecuadamente los requerimientos de DBAs, Admins y Seguridad Informática que “asoman”.

Los Web Front End servers de esta Web Application deben estar en la DMZ o red perimetral, dado que la Web Application en cuestión es Internet Facing.

Dado que la DMZ es una “zona no segura”, la DMZ no puede alojar ni a la capa de lógica de negocios ni a la capa de acceso a datos: solamente debería estar la capa de presentación de la Web Application en la DMZ.

Los requests y responses de los RPCs desde el código de la capa de presentación de la Web Application a la capa de lógica de negocios deben pasar a través de un firewall, por lo tanto, dichas invocaciones deberían estar “montadas” sobre el protocolo HTTP/HTTPS para ser viables.

Queda claro que la arquitectura típica presente en una cantidad importante de Web Applications existentes no es capaz de cumplir con las condiciones y requerimientos mencionados.

Por lo tanto, tal vez sea necesario revisar algunas de las decisiones de diseño que comúnmente se toman en Web Applications para que puedan cubrir estos requerimientos importantes de seguridad en forma adecuada.

En cuanto a los QAs de Mantenibilidad y Administrabilidad, podemos repasar brevemente como la forma en que registramos las excepciones arrojadas por la solución tienen implicancias cruzadas en ambos QAs.

Para los DBAs y Admins, sería conveniente que la solución registre las excepciones en el event log de cada server donde las mismas emergen, mientras que para el equipo de production support que ha de dar soporte (bug fixing e implementación de cambios de requerimientos) a la solución en producción, sería conveniente que la solución registre las excepciones en archivos de log en directorios de red a los que ellos tengan acceso.

Es importante destacar que el equipo de production support tal vez necesite que estos archivos de log registren detalles adicionales de las excepciones que serían un “exceso de información” para los DBAs y Admins, por lo tanto, las decisiones de diseño deberían cubrir en forma adecuada y equilibrada las diferencias en los detalles de información de excepciones a registrar para estos dos grupos.

En relación con el QA de Alta Disponibilidad/Disaster Recovery (HA/DR), debemos contemplar que si bien como primera aproximación es aceptable decir que las implementaciones de alta disponibilidad que soportan medidas de failover automático (como Failover Clustering y Database Mirroring, o las diversas configuraciones de AlwaysOn, en SQL Server) son transparentes a la lógica de los sistemas de información que las usan, lo correcto sería verificar con pruebas de carga con volúmenes y picos de transacciones comparables a los reales el grado de aumento de la latencia en las transacciones, debido a los procesos adicionales necesarios para el soporte de Alta Disponibilidad.

En suma, podemos encontrar que los requerimientos de todos los QAs mencionados tienen diversas y serias implicancias a nivel de las decisiones de diseño que permitan dar una cobertura apropiada a las requerimientos de DBAs y Admins que se desprenden (se “hacen visibles” a través) de dichos QAs.

Tarde o temprano, las decisiones de diseño que debemos tomar para dar adecuada y balanceada cobertura a todos los requerimientos derivan en una arquitectura distribuida, como una diversa cantidad de componentes a instalar en diversos servers.

No hay nada de malo en una arquitectura distribuida con diversos componentes a ser instalados en una serie de servers: es cierto, en sí mismo, no tiene nada de malo, pero debemos contemplar algunas de sus consecuencias.

Por ejemplo, un proceso manual de instalación y configuración de estos diversos componentes en diversos servers no es lo más recomendable, dado que podría ser propenso a diversos errores de instalación y/o configuración no evidentes (errores de instalación y/o configuración que no arrojan mensajes de error durante el proceso manual de instalación, configuración y prueba).

Para eliminar o mitigar la ocurrencia de este tipo de errores, es conveniente que contemos con procesos automáticos de deployment de los diversos componentes de la solución.

Pensar en cómo automatizar el deployment de la solución desde el comienzo

Ya hemos visto muy brevemente que debemos considerar con mucho detenimiento las decisiones de diseño que tomamos para asegurar una adecuada y equilibrada cobertura de todos los requerimientos de una solución, y además, hemos visto que las decisiones de diseño que tomamos tienen implicancias que afectan a estos requerimientos (por ejemplo, ya vimos como una arquitectura distribuida tiene implicancias en el deployment de la misma).

Por lo tanto, es necesario que empecemos a pensar en los procesos automáticos de deployment de la solución desde las etapas tempranas del diseño y del desarrollo, dado que si dejamos esto para el final, corremos el riesgo de descubrir (tarde) que algunas decisiones de diseño no “suman” a la automatización del deployment.

Es importante destacar que esto no implica trabajo adicional, sino que tan solo cambiar la decisión de que tan temprano se empieza a diseñar y desarrollar el proceso de deployment automático de la solución.

Para un equipo de desarrollo que utiliza Agile, debería ser algo bastante natural usar métodos automáticos de deployment.

Una de las prácticas de Agile es tener builds frecuentes durante la ejecución de una iteración o Sprint, como mínimo, en la medida de lo posible, un build diario, aunque sería mucho mejor si el equipo pudiese implementar un proceso de continuous delivery: poder realizar un build a pedido en cualquier momento, y si el mismo es exitoso, a continuación hacer un deployment automático a un entorno en particular de todos los componentes actualizados, recién generados en el build.

En sí mismo, para poder realizar un build a pedido, es necesario automatizar una serie compleja y larga de tareas, que incluyen procesos automáticos de copia coordinada de archivos a determinados directorios de red, junto con la invocación automática (y también coordinada) de determinados procesos (ejecución de procesos de verificación de estilos y standards de programación, ejecución de procesos automáticos de unit testing, ejecución de procesos automáticos de compilación y linking, etc.)

Los equipos de desarrollo Agile suelen usar determinadas tools open source para automatizar builds e integrations, tales como Ant o NAnt.

Por su parte, los DBAs y los Admins suelen usar tools como Perl, Python o PowerShell para automatizar procesos de administración.

Es altamente recomendable que los procesos automáticos de deployment, que han de ser ejecutados por los DBAs y Admins, estén desarrollados con las tools que los DBAs y Admins acostumbrar usar.

Por lo tanto, es altamente recomendable que el equipo de desarrollo adquiera la experiencia necesaria para desarrollar con fluidez en Perl, Python, PowerShell u otra tool, según corresponda.

Queda claro que tanto para el equipo de desarrollo como para el equipo de DBAs y Admins será de mucho valor agregado buscar formas de integrar el trabajo en conjunto que deben realizar.

Incorporar metodologías como DevOps para mejorar la integración con DBAs y Admins en los deployments

Qué podemos hacer para mejorar la integración del equipo de desarrollo con el equipo de DBAs y Admins?

A priori, esto parecería ser algo complicado de lograr, dado que, típicamente, el equipo de desarrollo usa procesos como Agile, por ejemplo, mientras de los DBAs y los Admins usan procesos como ITIL, por ejemplo.

A pesar que estos dos tipos de procesos parecerían presentar dificultades de reconciliación para poder pensar que sería posible tener procesos integrados, en realidad, es una tarea menos complicada de lo que parece, e inclusive, existen metodologías exitosas que permiten integrar los procesos de ambos equipos para aquellas tareas que deben diseñar e implementar en forma conjunta y coordinada.

Una de tales metodologías es DevOps

(para más detalles, ver definiciones y tools)

Como cierre, les dejo dos ideas para reflexionar:

“Los arquitectos debemos entablar un diálogo fluido, cordial y frecuente con los DBAs y Admins, de tal forma que seamos ‘todos juntos contra el problema’, en vez de ‘estar enfrentados por el problema’”.

“Si hemos de desarrollar soluciones que tengan a SQL Server como repositorio de persistencia, los arquitectos debemos ampliar tanto el alcance como la profundidad de los conocimientos que tenemos sobre las diversas capacidades que soporta esta herramienta”

Saludos, GEN

La tecnología nivela el campo: La Hora de los Más Chicos

umbrellaID-10023846

En el libro “El Arte de la Guerra” de Sun Tzu, el capítulo “Configuraciones de Terreno” contiene un párrafo muy relevador:

“Si podemos avanzar y el enemigo también puede avanzar, se llama ‘accesible’. En la configuración ‘accesible’, primero ocupa las alturas y el lado yang (soleado), y mejora las rutas para transportar provisiones. Luego, cuando nos trabemos en batalla, será ventajoso”.

Sun Tzu, en este párrafo, destaca a la vez que el terreno alto y soleado ofrece ventajas innegables al ejército que las ocupa, y que las posiciones niveladas no ofrecen ventajas diferenciales a ninguno de los contrincantes, y por lo tanto, el resultado de la batalla no está garantizado, sin la intervención de muchos otros factores cuyo orden de magnitud y combinación son tales que puedan desbalancear el resultado en favor del lado poseedor de los mismos.

Este párrafo es muy relevante respecto al panorama actual de tecnologías, redes sociales y software open source. Justamente, todas estos elementos dan lugar a un campo de batalla que presenta un terreno accesible, es más, totalmente nivelado, por lo tanto, el terreno es a la vez accesible y sin puntos elevados, por lo tanto, no hay lugares altos y a la vez, todos los sectores son lados yang (soleados).

En este contexto, la ventaja juega claramente a favor de los players más chicos, las PyMES, las empresas regionales, y definitivamente no juega a favor de las multinacionales, ni siquiera de las empresas nacionales más grandes.

Esta ventaja es concreta y posible, pero no puede realizarse si “los más chicos” no toman las medidas necesarias para hacer de estas ventajas una realidad.

Esas medidas necesarias implican un plan estratégico y una implementación de tal estrategia.

Tanto el plan estratégico como su implementación requieren claramente de una Arquitectura Empresarial y de un sistema de plataformas técnicas de negocios capaz de dar soporte a tal arquitectura, todos ellos alineados con el plan estratégico mencionado.

Saludos, GEN

Las redes sociales no aumentarán sus ventas por si mismas: debe alinear su arquitectura empresarial a su estrategia de negocios

BuildingID-10076694

Es interesante analizar brevemente como, en su gran mayoría, las empresas usan las redes sociales, las plataformas técnica de negocios y demás tecnologías para lograr sus objetivos de negocios.

A simple vista, el grueso de las empresas no sacan buenas calificaciones en esta área. Es más, resulta inclusive frustrante como espectador (y me imagino que para las mismas empresas debe ser aún más frustrante!) ver como el uso que hacen de estas tecnologías es correcto desde el punto de vista técnico, pero muy deficiente desde el punto de vista de estrategia de negocios.

Si bien es cierto que cada caso de cada empresa admite un análisis profundo para identificar los drivers de semejantes fallas sistemáticas, se destaca una falla por encima de todas las demás, en particular por su presencia generalizada en todo tipo de industrias, orígenes y tamaños de organización: fallas a nivel de arquitectura empresarial (en general, el caso más frecuente de falla es “Ausencia de una Arquitectura Empresarial”).

Sin una arquitectura empresarial que comande y guíe el despliegue de plataformas técnicas de negocios alineadas con las estrategias de negocios de la organización, las empresas seguirán obteniendo el mismo orden de resultados frustrantes provenientes del empleo de Twitter, Facebook, Youtube, Pinterest, Google Search, Google Maps y el combo que tenga ganas de agregar a esta lista.

Mientras las organizaciones no amplien las perspectivas y horizontes que orientan a los equipos de negocios que definen las arquitecturas empresariales vigentes, es poco probable que se perfilen cambios drásticos favorables en este sentido.

Saludos, GEN