Creando mejores agregados para optimizar el performance de un cubo (o el Data Warehouse)

19 09 2008

image

Muchas veces he visto cubos saturados de agregados. Los agregados son totales pre-calculados de la información y sirven para acelerar el tiempo de respuesta de las consultas.

Un agregado:

  • Ocupa espacio
  • Toma tiempo de procesamiento el llenarlo.

Lo anterior quiere decir que los agregados no son gratis.

Puede ser que un mes de información en la tabla de hechos ocupe 100 megas y los agregados para ese mes 50 megas. Tal vez llenar la tabla de hechos tome 10 minutos pero calcular los agregados tome una hora.

Así que no hay que crear agregados por crearlos, hay que analizar y poner en la balanza cuales realmente traerán beneficios y el costo que implicarán mantenerlos.

Los motores de cubos normalmente tienen un "query advisor" o parecido que pueden ayudar a sugerir los agregados. Hagamos de cuenta que esto no existe ¿cuáles pueden ser buenos agregados?

Pensemos:

Un agregado es un total de la información, si tengo un cubo, estrella o copo de nieve de ventas con 540 millones de registros y mi compañía se divide en 4 regiones (Norteamérica, América Latina, Europa y Asia) y quiero un agregado por región lo que obtendremos es una tabla con 4 registros. 1 registro con el total para la zona norte, uno para la zona sur, uno para la zona este y otro para la oeste.

Norteamérica $2,345,000
América Latina $1,934,567
Europa $2,567,000
Asian $2,200,000

Si quiero saber cuánto vendió la zona norte solo se barren únicamente 4 registros y no los 54 millones. Ahora, normalmente las regiones agrupan paises. Si quiero saber cuánto vendimos se vendió en la Canadá que pertenece a la zona norte no podemos usar el agregado anterior.

Lo que necesitamos es un agregado por Ciudad.

EUA $1,250,000
Canada $1,095,000
Inglaterra $1,490,000
España $1,077,000
China $989,000
Japon $1,211,000

Suponiendo que tenemos ventas en 20 países nos quedaría una tabla con 20 registros. Pero ahora el problema es que tengo 2 agregados, uno para resolver las consultas por ciudad y uno para las de región.

La mayoría de las herramientas OLAP pueden deducir un total a partir de su nivel inmediato inferior de granularidad. Esto es, debiera ser posible calcular el total por región a partir de las ciudades lo cual implicaría que no sería necesario tener los 2 agregados si no solamente uno. El de menor nivel. Las herramientas OLAP resuelven esto usando las jerarquías de las dimensiones, esa es una de las razones de establecer las jerarquías en Oracle o Analysis Services por ejemplo.

Cuando me ahorro agregados me estoy ahorrando espacio y tiempo de procesamiento del agregado.

Regresando al ejemplo anterior que pasaría si en cada ciudad tengo 3 tiendas, ¿no sería conveniente mejor realizar el agregado a nivel tienda (ya que tendríamos 20 x 3 = 60 registros) y ahorrarnos 2 agregados para matar 3 consultas diferentes? 60 registros para una tabla aun es nada

Bueno, la cosa no es tan fácil, tener un agregado sin incluir la dimensión tiempo no sirve de nada. Si queremos un total por mes necesitamos multiplicar por 12 la cantidad de registros, pero si nuestros usuarios consultan el detalle a nivel diario entonces tal vez nos interese el detalle mensual, entonces necesitaríamos multiplicar por 365 los registros.

Usted tiene que poner en la balanza que cantidad de registros es el máximo óptimo en un agregado.

Cosas que nunca haga, (ok, tips):

  • Si tiene una tabla de hechos cuyo menor nivel de detalle es cliente, producto entonces no haga un agregado x la combinación de cliente + producto por que estaría obteniendo un agregado con la misma cantidad de registros que la tabla de hechos Doh
  • Nunca haga un agregado con todas las dimensiones. Obtendría una tabla más grande que la tabla de hechos.
  • Incluya en el agregado todos los campos de la tabla de hechos así cuando esté realizando una consulta no planeada el usuario tendrá el mismo performance al incluir en la consulta los diferentes indicadores que el cubo tiene.
  • Normalmente no se requieren agregados a nivel muy granular, a nadie le sirve para un análisis saber cuánto vendí en $ de cada uno de los 158 mil 289 productos en el catálogo. Es muy importante saber el detalle de algunos de ellos (los de mayor venta). Bastará hacer agregados a los niveles superiores. Al hacer dril down en alguna tienda, alguna familia de productos, alguna categoría, la consulta se irá acotando. Bastará con algunos índices adecuados en la tabla de hechos para saber cuánto se ha vendido en la tienda 25 de algún producto.
  • A veces se requieren agregados exactos.
  • No olvide que los agregados siguen siendo tablas por lo que también es válido indexarlas.

PD: Si el motor OLAP que está usando no soporta jerarquías puede usar entonces un agregado compuesto: Región+Ciudad+Tienda; el efecto es el mismo ya que de un agregado se puede calcular el total de ventas por cualquiera combinación de las 3 dimensiones.





Como definir un cubo

5 09 2008

image

Tal vez esta sea una de las partes más complicadas sobretodo cuando uno apenas comienza. Un método que nosotros usamos bastante seguido es utilizar una matriz, por ejemplo:

Indicador/ Dimensión Tienda Producto Vendedor Ciudad
Ventas $ x x x x
Venta # x x x x
Descuentos x x x x
Nómina x   x x
Headcount x   x x

El concepto es sencillo, ponemos los indicadores en renglones y las posibles dimensiones en columnas. De esta forma visualmente tenemos la foto global de los cubos que serán necesarios construir. Normalmente aquellos indicadores que tienen exactamente las mismas dimensiones van en el mismo cubo.

Es importante que para este método usemos la dimensionalidad que técnicamente puede existir y no la funcional. Por ejemplo, para el caso de la nómina si tomamos el headcount a nivel vendedor el valor en dicho cruce será de 1 (el headcount es el # de personas que trabajan en la empresa) por lo que pareciera fácil decir que no tiene sentido el cruce y no la pondríamos, pero técnicamente es posible así que la ponemos….es más fácil hacer el cubo y en Artus esconder la dimension vendedor para el headcount que hacer un cubo con diferente dimensionalidad entre los indicadores y meterse a empatar dimensiones

Entonces, terminada la matriz, solo ponga en el mismo cubo todos aquellos indicadores que comparten las dimensiones.





¿Cuantas dimensiones puede tener un cubo?

24 04 2008

muchasdimensiones

Muchas veces me han preguntado esto ¿los cubos tienen un límite de dimensiones? Dependerá del software que utilice para hacer los cubos.

Tal vez el punto debiera ser ¿necesitamos tantas dimensiones? Lo que he visto en la práctica es que demasiadas dimensiones confunde y deja inservible el modelo. Hay que ser todo un experto en el diccionario de datos para saber que la dimensión 423 (llamada Depto E. por que ya nos acabamos todas las combinaciones de Depto.) es la que necesitamos ¿podrá tomar el usuario una decisión válida si no está seguro que el desglose de la información que está viendo a lo mejor no es correcta?

Por otro lado pocas dimensiones nos dejarán con el deseo de profundizar mas en el asunto.

dimensionesLos modelos de dirección para ser prácticos deben de andar entre 10 y 30 dimensiones. Mas 30 dimensiones y el modelo será operativo y difícil de dominar. En mi opinión creo se debería evaluar quien será el usuario del modelo y a partir de ahí determinar el # de dimensiones que será conveniente para dicho usuario.

No quiere decir que no se pueda (tener muchas dimensiones); se puede y muchas veces se tiene y se debe de hacer. Si es de los que tiene dimensionitis, puede agrupar las dimensiones para que al hacer drill down las dimensiones estén agrupadas según a la entidad que pertenecen (por ejemplo agruparlas por producto, por cliente, etc.)

Bueno, pero que mejor que todos para determinar que es mejor: ¿cuantas dimensiones has usado en promedio?¿ Te han funcionado? ¿te ha funcionado bién con muchisimas dimensiones?¿el usuario? ¿cual es el # máximo de dimensiones que has usado?¿cual es el tiempo de respuesta?¿cuál ha sido tu experiencia?…

Por cierto, en nuestro caso (Artus) se ha eliminado el límite de dimensiones que se pueden tener…

Liar

…ok, ok, dado que cla_descrip es un int, soportamos entonces 2,147,483,647 dimensiones, ese es el límite.





El modelo estrella

1 08 2007

Hay 2 modelos para crear un Data Warehouse, el modelo estrella o el copo de nieve. Yo prefiero el modelo estrella, ya que el tiempo de respuesta que provee es más rápido y hace que el servidor trabaje menos.

El concepto de Estrella es bastante sencillo. Hay que diseñar las tablas usando una tabla central para los hechos, tablas para los los catálogos y una tabla de tiempo.

ModeloEstrellaSales

El meollo del diseño de las tablas en el modelo estrella está en los catálogos. Tiene que poner en una sola tabla todo aquello que se pueda deducir del elemento más granular de la tabla y que está más abajo en la jerarquía.

Por ejemplo, si usted tiene un catálogo de productos, el elemento más granular es el producto ¿qué se puede deducir del producto? Pues la marca, el empaque, la presentacion (botella de cristal, PET no retornable, aluminio, etc.), la familia (bebidas), la subfamilia, la categoría, la subcategoria, el color, la talla si aplica, etc.

Bueno pues todo esto se coloca en la misma tabla.

El campo llave de esa tabla es el product_id (la llave de producto) por que producto (product) es el elemento más abajo en la jerarquía o más granular. Vealo de esta forma: una marca tiene productos, la familia agrupa productos, la subfamilia igual, la categoría igual, el color igual. El producto es el único que no agrupa a nadie, entonces esa es la la llave.

Si usted le hiciera un select a ese catálogo de productos el resultado sería el siguiente.

ResultSetEstrella

Puede ver que en el mismo registro se almacena el producto, la marca, la subcategoria, el departamento, la familia, la categoria. Todo lo que se puede deducir del producto está ahí.

Lo mismo pasa con las tiendas. De la tabla de tiendas (ver tabla Stores en el diagrama) se puede deducir la region y el pais al que pertenece. Entonces pais y región los pongo en la misma tabla que tienda.

Para mejorar todavía más el tiempo de respuesta coloque en la tabla el campo llave y el descriptor como se muestra en la siguiente imagen.

ResultSetEstrella1

Si hace esto en el query SQL que escriba para obtener datos de la estrella podrá usar:

where
   IdBrand = 15

en véz de:

where
   Brand = ‘Washington’

Tendrá un mejor tiempo de respuesta si usa llaves. Entonces siempre en los catálogos ponga además de los descriptores el campo llave de cada descriptor.

TIP: Si está pensando crear un cubo con los Analysis Services de Microsoft usando esta estrella, el poner la llave en la estrella hace que el cubo se reduzca de tamaño y el tiempo de respuesta se acelere. Solo tenga cuidado de que al crear la dimensión, en propiedades de la dimensión ubique y use la propiedad “llave de la dimensión”.

TIP: Para las llaves trate de que siempre sean numéricas y de no usar llaves compuestas.

TIP: Si va a seguir el tip anterior, puede ayudarse poniendo en los catálogos además de la nueva llave inventada por usted, la llave original para la dimensión. Yo siempre las identifico con Id y Cve, la que termina en ID es inventada por mí y la que termina o comienza en CVE es la original.

¿A partir del producto yo puedo deducir en que tienda se vendió? Suponiendo que hablamos de supermercados y en cada tienda se pueden vender los mismos productos entonces la respuesta es NO, no se puede deducir qué tienda vendió qué producto. Esto se resuelve en la tabla de hechos poniendo ahí que producto se vendio (producto_id), en que tienda (store_id) y en que día (time_id).

Esto es el modelo estrella.

IMPORTANTE: No se quede con la idea que al hacer los catálogos redundantes va a desperdiciar todo el disco duro. La redundancia es solo en los catálogos no en los hechos, usted puede tener un catálogo de 100,000 productos pero millones y millones de transacciones. Lo que hace que un datawarehouse crezca normalmente es la tabla de hechos. Si todavía está renuente y saca a relucir las reglas de Codd de normalizacion, para no entrar en polémica digamos que este es uno de los extraños casos donde lo que aprendió en la universidad lo puede tirar a la basura Big Grin.

Para complentar esto puede consultar los posts La tabla de hechos y Algunas recomendaciones para la tabla de hechos. Respecto a la tabla de tiempo (TimeDim) puede leer La dimensión tiempo y los otros campos de la tabla de tiempo.

Si quiere ver como convertir una estrella a un cubo puede consultar como hacer un cubo con Artus.





Haciendo un cubo con Artus

1 08 2007

ModeloEstrellaVentasChico

Entrando de lleno al tema, lo primero que se necesita para hacer un cubo con Artus es una estrella que contenga la información. Es decir, usted debe de construir unas tablas siguiendo el modelo estrella y llenarlo con datos. Un modelo estrella no es otra cosa que una tabla con catálogos.

Para hacer este tutorial previamente preparé un modelo estrella y para hacer más fácil esto, la puse en access y está disponible aquí. Bájelo y descomprímalo en un directorio que le sea fácil de recordar; luego cree un ODBC que apunte a esa base de datos. El que yo cree en mi máquina para el tutorial le puse el nombre de Estrella, igual que el nombre de la base de datos de Access.

A la izquierda puede ver el diagrama entidad relación de la base de datos. Es un pequeño ejemplo de ventas de un supermercado. Retail dirá alguien.

Por cierto, en la vida real Access no es una buena opción para almacenar estrellas. Normalmente usted usará un motor SQL más poderoso como Oracle, SQLServer o DB2 para esto. En castellano, en la vida real no ponga las tablas en access si no en un SQLServer, Oracle u otra base de datos relacional que tenga ahí a la mano. Si no me cree, ponga en una base de datos de access más de 1 giga de información.

Leer el resto de esta entrada »





El cubo no trae datos

20 07 2007

Procesa

A veces me preguntan por que mi cubo no trae datos.

—Lo procesé y de repente los datos desaparecieron…

Una forma sencilla de saber por que no trae datos es procesarlo y esperar a que termine el proceso. Cuando eso ocurra, hay que darle 2 clic sobre el icono SQL que aparece ahí. Al darle 2 clic, Análysis Services me trae el SQL que el lanza sobre el Data Warehouse para llenar el cubo. Solo es cuestión de revisar por que el query no devuelve datos.

Esto no pasa de repente, el query se construye en base al diagrama que hayamos hecho al hacer el cubo, en base a que campos están marcados como indicadores y cuales como dimensiones

Technorati tags: ,





El problema del inventario

17 07 2007

inventario

Para resolver el problema del inventario donde el indicador no se suma si no lo que se quiere es el último valor; podemos usar MDX dentro de Artus para traernos el valor al cierre del periodo. De esta forma el total del mes no será la suma del inventario de cada día del més sino del último día.

La función quedaría así:

[(Measures.[Value], ClosingPeriod([Month])]

Solo sustituyan la palabra Value por el nombre real del indicador y Month por el nombre real de la dimensión y periodo para el cual desean encontrar el valor.

Hay muchísimos casos diferentes; a lo mejor quiero el último valor encontraro, el que si no lo encuentro me dé el del mes pasado, etc.. Aquí en MSDN pueden encontrar un excelente documento que muestra varios casos relacionados con el tema.

Para los que usen Analysis Services con Artus: Todos los casos en el documento se pueden implementar con Artus.

MDX es el lenguaje que Microsoft Analysis Services proporciona para acceder a los datos del cubo, nó Artus. Así que tendrán que investigar en la ayuda proveída por Microsoft. A veces la liga cambia así que lo  pueden encontrar en el Widget de Box en el lado derecho.

Por cierto, es preferible crear el indicador calculado en el cubo de Analysis Services y luego importarlo a Artus. Solo tomen en cuenta dejar el indicador como:

([Measures].[InventarioDinero_DEPENDSONDIMENSION])

Concatenándole la palabra: _DEPENSONDIMENSION

Technorati tags: ,




La dimensión Tiempo. Los otros campos

3 07 2007

Continuando con la dimensión de tiempo, también están los otros campos que son muy importantes. Debemos considerar el campo Fecha que dependiendo de la base de datos será de tipo DATE, DATETIME o algo parecido.

tiempo2

Debemos de incluir un campo Año donde se almacenarán los valores 2006, 2007, etc. Aquí no hay mucho que decir.

Para el campo mes muchas veces me he topado con que los valores que se guardan ahí son: Ene, Feb, Mar; o Enero, Febrero, Marzo. Si hacemos esto de guardar solo la parte mes, cuando lancemos un query sobre la estrella deberemos poner en el where la parte año para que la consulta no sume los datos de los mismos meses de todos los años.

Un ejemplo de como se vería el query sería:

SELECT MES, SUM( VENTAS)
FROM HECHOS A, TIEMPO B
WHERE A.TiempoID = B.TiempoID
AND AÑO IN (2006,2007)

En este ejemplo, estaría sumando ENERO del 2006+ENERO del 2007. Para que esto no ocurra es mejor guardar en el campo mes el valor junto con el año en la siguiente forma: YYYY MMM. Por ejemplo, 2006 Ene, 2006 Feb, 2007 Ene. También se vale poner el nombre completo del mes: 2006 Enero.

tiempo3 Podemos mejorar el diseño de la tabla de tiempo como se muestra a la derecha. Se añadió a la tabla el campo MesID. De esta forma en el campo mes guardamos 2006 Ene y en el MesID guardamos 200601. Así podremos decirle en el query que me muestre el campo Mes pero que lo agrupe y ordene por el MesID.

SELECT MAX( Mes ), SUM( VENTAS)
FROM HECHOS A, TIEMPO B
WHERE A.TiempoID = B.TiempoID
GROUP BY B.MesI
D
ORDER BY B.MesID ASC

Lo mismo ocurre para la Semana, Trimestre, Época del año, Quincena y cualquier otro campo que se quiera añadir para agrupar los días. Tendré el campo por el que lo visualizo y el campo por el que lanzo el query y lo controlo.

Respecto al día de la Semana ahí no es necesario concatenarle el año o mes o semana en el valor por que lo que normalmente queremos hacer es agrupar los lunes con los martes y miércoles para ver como se comportan. Aquí si se quieren agrupar los Sábados de todo el año por ejemplo.

Observen como se ha cuidado que los campos ID sean de tipo INT. Esto debido que a la base de datos le es más fácil trabajar con números.

Para obtener un script que cree la tabla de tiempo y la llene dé clic aquí.

Technorati tags: , , Data warehouse





La dimensión Tiempo

2 07 2007

Estrella

Cuando estamos diseñando las estrellas o copos de nieve que formarán nuestro data warehouse, hay que tener mucho cuidado con la dimensión de tiempo. Hay varias formas de hacerlo y para mi gusto unas mejores que otras. La forma más común de encontrar es una en la que el campo llave es la fecha.

tiempo1

Aquí a la izquierda está el típico diseño. El problema aquí es que a las bases de datos les cuesta trabajo hacer búsquedas por campos datetime o date, al menos más que un campo entero. Otro punto es que el campo fecha ocupa más espacio que un campo entero. Hay que tomar muy en cuenta que el campo fecha, que es la llave, formará parte de la tabla de hechos; y con millones y millones de registros un byte o dos es mundo de espacio, tal vez un disco duro :) .

tiempo2

Podemos mejorar el diseño cambiando el campo llave por un campo entero como en la figura de la derecha. Esto hará que:

  • las búsquedas sean más rápidas sobre todo en la tabla de hechos. Esto por que a las bases de datos les cuesta menos trabajo manejar números que fechas, o sea ocuparemos menos el procesador y ocuparemos menos memoria.
  • Que el tiempo de respuesta sea más rápido. No es redundancia, este punto es una consecuencia de lo anterior.
  • Que físicamente los datos ocupen menos espacio. De nuevo, el servidor trabaja menos con menor volumen de información y se requieren menos procesador y menos memoria o sea que la ganancia es doble. 

En este diseño hay 2 corrientes, los que usan un numero consecutivo como llave y los que usamos un numero en el formato yyyyMMdd. Para mi gusto es muy frustrante encontrarse una estrella donde la llave de la tabla tiempo es un 1,2,3,4…34560,34561,….@#$%#$$% ¡para saber a que fecha corresponden el 34561!…pues hay que hacerle un query a la tabla de tiempo.

Yo prefiero de llave un numero con el formato yyyyMMdd, así para el 31 de diciembre del 2007 guardo 20071231 en el campo TiempoID, sigue siendo un numero entero y es mucho más legible que un simple 1-2-3. Con solo ver que valor tiene el campo TiempoID puedo saber a que fecha corresponde el registro. Además funciona perfectamente en el where con un between:

SELECT *
FROM HECHOS
WHERE TIEMPOID BETWEEN 20070101 AND 20070131

Hay un punto no tan visible con el campo llave:  la tabla de hechos tiene índices para acelerar el tiempo de respuesta. Los índices ocupan espacios y si usamos un campo entero en vez de un datetime estaremos ahorrando espacio y haciéndole la vida más fácil al servidor.

En bases de datos pequeñas 1 a 10 gigas da lo mismo usar uno u otro. En bases de datos gigantes como las de grandes tiendas departamentales o tiendas de conveniencia donde la base de datos del data warehouse mide teras usar un campo entero es de vital importancia.

En otro post analizaremos los demás campos de la tabla de tiempo.

Para obtener un script para crear y llenar la tabla de tiempo dé clic aquí.

Technorati tags: , , Data Warehouse





Indicador Compuesto

29 06 2007

Este es un ejemplo de un indicador compuesto….

Iif(IsNull(iif(([Measures].[Venta Total] > -0.1 and [Measures].[Venta Total] < 0.1) or ([Measures].[Mes Real Corp] > -0.1 and [Measures].[Mes Real Corp] < 0.1), 0, (([Measures].[Mes Real Mes Ant]- [Measures].[Venta Total]) / Abs([Measures].[Venta Total]))*100)), null, Iif([Measures].[Signo] = 1, Iif(iif(([Measures].[Venta Total] > -0.1 and [Measures].[Venta Total] < 0.1) or ([Measures].[Mes Real Total Suc] > -0.1 and [Measures].[Mes Real Total Suc] < 0.1), 0, (([Measures].[Mes Real Suc]- [Measures].[Venta Total]) / Abs([Measures].[Venta Total]))*100) > 3, iif(([Measures].[Venta Total] > -0.1 and [Measures].[Venta Total] < 0.1) or ([Measures].[Mes Real Corp] > -0.1 and [Measures].[Mes Real Suc] < 0.1), 0, (([Measures].[Mes Real Suc]- [Measures].[Venta Total]) / Abs([Measures].[Venta Total]))*100), 0), Iif(iif(([Measures].[Venta Total] > -0.1 and [Measures].[Venta Total] < 0.1) or ([Measures].[Mes Real Suc] > -0.1 and [Measures].[Mes Real Suc] < 0.1), 0, (([Measures].[Mes Real Corp]- [Measures].[Venta Total]) / Abs([Measures].[Venta Total]))*100) < -3, iif(([Measures].[Venta Total] > -0.1 and [Measures].[Venta Total] < 0.1) or ([Measures].[Mes Real Suc] > -0.1 and [Measures].[Mes Real Corp] < 0.1), 0, (([Measures].[Mes Real Suc]- [Measures].[Venta Total]) / Abs([Measures].[Venta Total]))*100), 0)))

¡Changos!  :shock: ¡y quieren que el tiempo de respuesta del servidor sea de un segundo!

Habrá que ponerle esteroides… :grin:

Technorati tags: ,







Seguir

Get every new post delivered to your Inbox.