jueves, 20 de enero de 2011

Problemas de compatibilidad entre SSIS 2008 y Denali

Hola amigos. Después de algún tiempo buscando un rato que dedicarle a la nueva entrega de SQL denominado en nombre clave Denali me he llevado una torta en la frente.
Se me ocurrió instalar una instancia de Denali en un servidor de desarrollo dónde ya existían instancias de SQL 2005 y 2008 R2. El problema surge cuando se intenta abrir un proyecto de SSIS construido con BIDS 2008… ahora el proyecto es incompatible!
No capturé la pantalla pero os dejo el mensaje que devuelve:
(modal window)
---------------------------
Microsoft Visual Studio
---------------------------
'C:\Users\Atharky\AppData\Local\Temp\sample.dtproj' cannot be opened because its project type (.dtproj) is not supported by this version of the application.

To open it, please use a version that supports this type of project.
---------------------------
OK Help
El problema es que Denali trabaja con el shell de Visual Studio 2010, pero en este CTP1 aún utiliza el Visual Studio 2008, total que no se entiende con sus hermanos pequeños, por ahora.
Si vosotros también reproducís este error, os recomiendo que votéis el caso a ver si lo solucionan en la próxima entrega: https://connect.microsoft.com/SQLServer/feedback/details/637105/incompatiblity-error-open-ssis-2008-project-after-install-sql-denali
También es verdad que la incidencia está documentada en algún blog desde noviembre, pero lo vi tarde! Espero que para vosotros no lo sea.

**************************************************************************************

[21.01.20111] Updates

He encontrado algunos enlaces interesantes a leerse antes de hacer la instalación.

Microsoft Notes :

How to: Install SQL Server "Denali" ; SQL Server Code-Named “Denali” CTP1 Release Notes
Download Microsoft® SQL Server® code-named ‘Denali’(CTP 1)
Video : How to Install SQL Server 2008 ; SQL Server 2011 – New Version Release

 

 

 

Un saludo!

miércoles, 12 de enero de 2011

miércoles, 5 de enero de 2011

SSIS Dinamizando propiedades de componentes

 

Es bastante usual tener que utilizar distintas configuraciones a la hora de ejecutar un mismo componente en un paquete ETL, por ejemplo: Si tenemos varios ficheros de texto que queremos cargar en un destino en el mismo proceso. Otro ejemplo bastante ilustrativo es la utilización de una tabla de valores para almacenar y extraer los datos de conexión para un fichero en un ftp. Normalmente, quien no ha trabajado con propiedades dinámicas se encuentra con algunas dificultades que intentaremos mencionar y resolver a través del último ejemplo.

Dinamizando propiedades: FTP Task

El escenario es el siguiente: necesitamos obtener de distintos servidores/rutas FTP algunos ficheros para almacenarlo en algún sitio.

La aproximación más bruta es agregar un componente por cada fichero a descargar y configurar sus propiedades específicas. Es perfectamente válido, pero imagina que tienes más de 100 ficheros que descargar y en el futuro puede ampliarse o variar la configuración de cada uno. Como digo, es posible y factible pero no práctico y fácil de mantener.

Escenario

Vamos a crearnos una tabla en SQL (o Excel o Access o un TXT, pero ya que vamos a hacerlo bien… un SQL Sonrisa). 

create table FTP_DownloadConfigurations (

idConfig int not null identity (1,1),

DNS varchar(255),

[Path] varchar(255),

[File] varchar(255),

[Created] datetime not null default(getdate())

)

Los campos que vamos a utilizar son DNS, Path y File para localizar el fichero a descargar y pasar como propiedades a la tarea FTP de SSIS.

Para este ejemplo he creado dos entradas en la tabla, accediendo a FTPs públicos:

image

Construyendo la base

Lo siguiente es armar el esqueleto de nuestro paquete:

image

Nos creamos una variable de tipo Object que llamamos Configuraciones o cómo os dé, pero lo importante es saber que aquí tendremos el recordset, el contenido de la tabla creada anteriormente.

image

También tendremos que añadir variables para recoger el valor de cada campo en el ForEach.Ojo con el ámbito de la variable, debe ser común a todos los componentes, en este caso, al menos la variable DNS debe ser del ámbito de todo el paquete ya que será necesario utilizarla para dinamizar la conexión FTP.

image

 

Obtener configuración dinámica

Configuramos el ExecuteSQL para que nos devuelva las filas de configuración que nos interesan, en nuestro ejemplo todas. Es importante configurar la opción ResultSet a Full Result Set.

image

Para terminar la configuración del componente nos movemos hasta la sección Result Set y establecemos la variable que va a recoger el resultado:

image

Configurar el Bucle

Pasemos al siguiente componente, el bucle foreach para recorrer el recordset. Abrimos el su editor y establecemos el tipo de foreach a Foeach ADO Enumerator. Seleccionamos también la variable Configuraciones que contiene el recordset.

image

En la sección Variable Mappings, asignamos las variables que que recogerán los campos del recordset: DNS, Path y File. Es importante respetar el orden de los campos, y configurarlos en el mismo en el que hemos realizado la consulta:

image

 

Configurando la Tarea FTP

En este componente haremos uso del resto de   variables y hay que configurar las propiedades y expresiones para que tenga un comportamiento dinámico. Abrimos el editor del FTP Task y lo primero que nos solicita es una conexión FTP que no hemos creado. Pulsamos sobre Nueva Conexión

image

En el editor de la conexión FTP escribimos cualquier dirección FTP real o inventada, para que pueda validarse el formulario. Cuando hayamos pulsado aceptar, nos vamos al panel de Administradores de Conexiones, seleccionamos nuestra conexión FTP y pulsamos F4 para ver sus propiedades. Busca la propiedad Expressions y abre el formulario de asignación de expresiones pulsando el botón de los tres puntos…

image

Buscamos la propiedad Connection String y pulsamos sobre el botón editar […]. Asignamos la variable User::DNS

image

 

Y salimos de la configuración del administrador de conexión FTP para volver al componente Tarea FTP. La configuración de dinamización puede confundirse con el uso de variables para la configuración del componente. No es lo mismo configurar un componente para que tome un valor para una propiedad desde una variable que asignarle una expresión en función de una  o múltiples variables. Las expresiones puede formarse por variables, pero no sólo por ellas.

Para entender la diferencia, vamos a crearnos otra variable que llamamos LocalPath de ámbito del contenedor de secuencias y le establecemos el valor c:\temp o cualquier otra ruta dónde queramos descargar los ficheros.

En la configuración del FTP Task, en la sección File Transfer configuramos las propiedades según la siguiente tabla:

Propiedad Valor
IsLocalPathVariable True
LocalVariable User::LocalPath
Operation Receive Files
IsRemotePathVariable False
RemotePath /pub/mozilla.org/firefox/nightly/latest-mozilla-central/firefox-4.0b9pre.en-US.win32.installer.exe

 

image

 

Si se dan cuenta, la propiedad IsLocalPathVariable la hemos configurado para que tome el valor de la variable LocalPath. Por el contrario el path remoto lo hemos escrito.

Accedamos a la sección Expressions. Editamos la expresión para la propiedad RemotePath = User::Path + User::File.

 

image

¿Qué pasaría si también configuramos la propiedad LocalPath desde expresiones? Devolvería un error diciendo que no encuentra la variable con nombre de variable con el contenido de nuestra variable LocalPath, en nuestro caso c:\temp…..

Ultimando detalles

Sólo queda configurar la propiedad DelayValidation del FTP Task y del administrador conexión FTP a True para que no intente probar la conexión antes de ejecutar.

 

Y a correr!

image

 

 

Si no les queda claro algo, coméntenlo y lo vemos.

 

Saludos!


martes, 4 de enero de 2011

SSIS SCD Componentes alternativos

 

En la entrada anterior vimos como sustituir el componente Slowly Changing Dimension mediante técnicas de diseño y utilizando componentes provistos por SSIS de forma nativa. Existen alternativas a la técnicas de diseño más conjugaciones utilizando componentes de terceros gratuitos.

En Codeplex, sitio de Microsoft para proyectos de código abierto, existe el proyecto Kimball Method SSIS Slowly Changing Dimension Component, desarrollado entre otros por Todd McDermid (un maestro en SSIS). Publica los cambios y actualizaciones del componente en su blog. En definitiva, este componente optimizado y basado en la metodología de Kimball para datawarehousing tiene un rendimiento 100x veces superior al SCD nativo de SSIS.

Os dejo la dirección del proyecto en Codeplex, dónde aparte del componente podréis encontrar videos didácticos sobre la aplicación de metodologías para el mantenimiento de tablas de dimensión http://kimballscd.codeplex.com/

Un saludo

lunes, 3 de enero de 2011

SSIS Slowly Changing Dimension y alternativas


En este post hablaremos sobre el diseño de dimensiones y algunas aproximaciones para gestionar su mantenimiento con Integration Services.
En el diseño de una dimensión es necesario clasificar el tipo de cambio que se implementa a cada atributo. aunque en la wikipedia existe una entrada sobre este tema en la que describen hasta seis tipos, nos centraremos en los tres más usuales, :
  1. Tipo 0. Este método contempla hacer nada con respecto cambios en el valor original. Ni se actualiza ni se crea histórico, simplemente mantiene el valor del atributo cuando se generó la fila en la tabla de dimensión.
  2. Tipo 1. Cuando se detectan cambios en el origen, el valor del atributo se sobrescribe de manera que se pierde el histórico.
    image
  3. Tipo 2. Este tipo implica crear un registro histórico por cada cambio contemplado en el valor de origen y requiere al menos una clave de negocio o business key o natural key. Cuando se detecte que el valor de alguno de los atributos de tipo 2 se ha modificado, se crea una nueva fila en la tabla de dimensión con los nuevos valores. Para poder determinar que fila es la actual será necesario implementar algún mecanismo, como la evaluación de campos con la fecha de validez del registro o un campo booleano.
Vamos a ver como lo hacemos con campos de fecha:
image
Para este seguir método se hace necesario utilizar una clave propia de la dimensión, una clave surrogada o surrogate key. Normalmente un campo identity de la tabla .De forma es posible asignar a los nuevos hechos la fila de la dimensión adecuada.
image
Como se puede apreciar en la imagen de ejemplo, para gestionar la nueva fila se ha actualizado la fila anterior introduciendo un valor en el campo EndDate que contendrá en la que se generó el cambio. Hay que observar que se mantiene la clave de negocio que se utiliza para realizar las comparaciones entre origen y dimensión y la clave surrogada que se utilizará para asignar a los nuevos hechos.
Una vez hecho el repaso general, vamos a ver como resolver el mantenimiento de una tabla de dimensión con los tres tipops de atributos sin utilizar el componente  Slowly Changing Dimension.
¿Y por qué no utilizar el componente SCD incluido en SSIS? Pues sobre todo por deficiencias en rendimiento. Si, es un componente muy cómodo de utilizar y si el número de miembros en la dimensión (filas) es reducido, podremos emplearlo sin que se note demasiado. Básicamente realiza una comparación fila a fila para evaluar los distintos tipos de cambios y posteriormente utiliza un componente OLEDB Command para ejecutar las actualizaciones, también fila a fila. En resumen, si hay muchas filas genera muchas operaciones que realmente no son necesarias o mejor dicho, se pueden optimizar. Puedes utilizar el SQL Profiler para examinar este comportamiento, verás que ejecuta el procedimiento sp_executesql con el la clave de negocio como parámetro.
Siguiendo el ejemplo anterior, vamos a diseñar un paquete mantenga una tabla de dimensión con estos tres tipos de atributos.
Podemos utilizar Lookups o Merge Join como alternativas al SCD.
Lookups
En SQL Server 2008 el componente de búsqueda o Lookup tiene alguna opción de configuración más que la versión 2005 para gestionar las salidas de filas: Redirigir las filas no coincidentes a un salida.
image
Esto nos facilitará el diseño de nuestro paquete.
Supongamos un diseño básico con un origen de datos. Creamos la columna que establece la fecha de inicio de validez del registro con un componente Columna Derivada. Vamos utilizar la fecha de procesamiento del paquete para la columna StartDate:
image
Es posible que las reglas de negocio obliguen a utilizar una fecha de validez distinta, por ejemplo la fecha de modificación del registro en el modelo transaccional.
Añadimos un componente de búsqueda y configuramos la conexión para la base de datos dónde tengamos la tabla de dimensión, el datawarehouse o datamart y seleccionamos la opción Usar el resultado de una consulta. Hay que modificar la consulta para obtener sólo las filas válidas de la dimensión:
image
En la sección columnas, seleccionamos todas la de destino y asignamos un alias a cada una para poder distinguirlas de las columnas de origen:
image
De esta forma incorporamos al flujo todas las columnas del destino.
Para la filas nuevas, que obtendremos en la salida de filas no coincidentes añadimos un componente OLEDB Destination y las insertamos en la tabla de dimensión:
image

Ahora nos queda comparar los valores y actuar en función del tipo de cambio por atributo, para lo que conectaremos un componente Conditional Split a la salida de filas coincidentes del Lookup
Creamos dos salidas para los tipos de cambio 1 y 2, para lo que comparamos los campos de origen con los de destino. En nuestro ejemplo, el campo Country será de tipo 2 y el campo Phone será de tipo 1. Es importante el orden ya que las filas sólo se evalúan una vez, es decir, si cumple la primera condición será redirigida a la primera salida. Por tanto en primer lugar habrá que comparar los atributos (campos) de tipo 2 que generan una nueva fila con todos los valores nuevos y posteriormente los de tipo 1.
image
Añadimos una columna derivada para establecer la fecha de fin.Este es el campo que utilizaremos para asignar la fecha de caducidad del registro.
image
En el flujo de datos, añadimos un componente Multidifusión que conectamos a la salida de la columna derivada.
A una de las salidas de Multidifusión conectamos un Unión de todo. Utilizamos la salida de cambios de tipo 1 del componente División condicional y lo conectamos al Unión de todo.
Y ahora hay que prestar atención: En el Unión de todo configuramos el campo NuevoEndDate de la entrada 1 y lo mapeamos con el campo Destino.EndDate la entrada 2 de datos:
image
Si hemos seguido las indicaciones, en la entrada 1 de datos tendremos los cambios de tipo 2, por lo que utlizamos la fecha creada para establecer caducidad. En el campo Destin.EndDate también podemos dejar Null.
A la salida del Unión de todo conectamos un nuevo Destino OleDB. Para este destino es necesario crear una tabla con la misma estructura que la de dimensión pero con el campo SurrogateKey sin identity. Esta tabla nos servirá de Stage para poder ejecutar posteriormente una consulta de Update en un Ejecutar SQL en el flujo de control en lugar de un Comando OleDB.
En el mapeo de campos tendrás que tener en cuenta que debes guardar la clave de dimensión para poder ejecutar un update:
image
Como no hemos dicho nada acerca de los campos Name y Code, mantendremos los valores existentes en la dimensión.
Al final, el diseño del flujo de control tiene que tener un aspecto parecido a este:
image

Para terminar, añadimos al flujo de control un componente Ejecutar SQL añadimos dos consultas: Un update entre DimClientes y DimClientes_Updates y un truncado de esta última.
image

Y Tachán, ya tenemos listo un paquete para el mantenimiento de una dimensión con cambios tipo 1 y tipo 2. Se puede complicar más el diseño haciendo updates separados para cada tipo de cambio.
Si la dimensión tiene una cantidad de filas considerable, que no puedan cargarse en el caché del componente Lookup, podemos sustituirlo por un Merge join, solo que habría que utilizar el Conditional Split que tenemos en el flujo para detectar las filas nuevas.

Espero que os sirva, Saludos!

Entradas populares