Postgre: Instalación y configuración básica

Hace no mucho me toco para una prueba de concepto instalar Postgre en un servidor con Ubuntu 16.04. Los pasos para instalar en otra versión de Ubuntu similar o Debian deberían ser los mismos. No entro mucho en detalles porque solo necesitaba un pequeño ambiente para hacer una prueba de concepto.

Para empezar, necesitamos una consola abierta en Linux y permisos de sudo (pida ayuda a su persona de IT mas cercana). Para instalar Postgre, alcanza hacer:

$ apt-get install postgresql postgresql-contrib

¿Pero que sucede si queremos instalar una versión especifica de Postgres?
En este caso, tenemos que agregar el repositorio de Postgre y luego indicar la versión que necesitamos:

$ sudo add-apt-repository "deb http://apt.postgresql.org/pub/repos/apt/ $(lsb_release -sc)-pgdg main"
$ wget -q -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -

Para instalar por ejemplo la versión 9.6 de Postgre, podemos ejecutar el siguiente comando:

$ sudo apt-get update
$ sudo apt-get install postgresql-9.6 postgresql-contrib

Una vez que termine la instalación, podemos verificar si se instalo correctamente conectándonos de la siguiente forma:

$ sudo -u postgres psql postgres

Con eso deberíamos loguearnos a la consola de Postgres. Podemos verificar la versión de Postgre instalada corriendo la siguiente consulta:

SELECT version();

Ya deberíamos tener todo lo que necesitamos para crear una base. Sin embargo, por default, Postgre no permite conexiones remotas. Para hacer eso, debemos seguir los siguientes pasos:

Vamos primero a buscar el archivo postgresql.conf (usualmente esta en /etc/postgresql/9.6/main/postgresql.conf). Allí dentro debería existir la opción:

#listen_addresses = 'localhost'         # what IP address(es) to listen on;

Sacamos el ‘#’ de adelante y modificamos ‘localhost’ y lo reemplazamos por ‘*’.

ATENCIÓN: Esto hace que todos puedan conectarse a nuestro Postgre dentro de la red. Si solo queremos limitarlo a un grupo de IPs podemos listar las mismas separadas por comas dentro de las comillas de la siguiente forma: ‘10.0.0.10, 10.0.0.11’.

Guardamos los cambios y salimos del archivo y ahora vamos a buscar otro archivo (en principio en la misma carpeta) que se llama pg_hba.conf. Aquí, debería haber una linea que diga algo como:

host all all 127.0.0.1/32 md5

Lo modificamos para quede de la siguiente manera:

host all all 0.0.0.0/0 md5

Finalmente hacemos reiniciamos el servicio de Postgre ejecutando el siguiente comando:

$sudo /etc/init.d/postgresql restart

Esto debería dejarles Postgre corriendo y permitiendo que otros se conecten a su base de datos. Tengan en cuenta que para conectarse remoto y ejecutar consultas SQL probablemente necesiten un usuario con password (por ejemplo para usar el pgAdmin). Si es el caso simplemente creen un usuario en la consola de postgre haciendo:

CREATE USER admin WITH ENCRYPTED PASSWORD '';

Luego denle los permisos que quieren que tengan y ya deberían poder conectarse desde el pgAdmin de manera remota (el cual les recomiendo que se bajen para administrar Postgre).

Espero les sirva,
Alejandro

Anuncios

Data Lake: Como encarar el proyecto

Voy a empezar con un “DISCLAIMER”. Esto es, más que una metodología, una forma de pensar en como empezar a llevar adelante la incógnita en el titulo. Parto de la base que si estamos aquí, es por qué ya sabemos que es un Data Lake y no voy a entrar en demasiado detalle aunque si repasar algunos conceptos para poder entender por qué tomo alguna decisiones a la hora del diseño. Este no es un método infalible y lo voy a ir modificando a medida que gane experiencia al diseñar los mismos. Con mi corta experiencia, si alguien tiene alguna sugerencia, les pido que comenten para aportar a la discusión. Probablemente esto se convierta en una cadena de posts.

Empezando, deberíamos repasar una serie de preguntas:

  1. ¿Como se va a usar el Data Lake? O en otras palabras ¿Que uso le van a dar los usuarios a los datos?
  2. ¿Que información vamos a guardar?

Estas son en realidad, dos preguntas clásicas para diseñar una base de datos. La primera habla de la perspectiva de como los clientes usan los datos, y la segunda nos habla de que información necesita el cliente para hacer sus reportes o análisis. La realidad, es que el cliente siempre va a pedir algo del estilo “pone todo en el Data Lake” pero es nuestro trabajo tratar de enfocar al cliente primero en conseguir lo que el realmente necesita y no otra cosa. Lo primero que tenemos que entender es que el Data Lake no es un tacho donde ponemos cualquier cosa. Al Data Lake, solo va la información que entendemos para  que sirve y como se combina con el resto de la data que esta ahí, sino se convierte en el infame “Data Swamp”.

Ahora ¿para que se usa un Data Lake? En general, en base a experiencia personal, para análisis lo que quiere decir una cosa a nivel diseño de bases de datos: es un modelo desnormalizado. Esto se debe principalmente a dos motivos:

  1. El cliente va a estar consultando mucha información a la vez en el DataLake, por lo tanto tenemos que evitar que tenga que hacer muchos JOINs.
  2. Para hacer análisis, es poco probable que la información se actualice en vivo. En general, los analistas hacen escaneos de información en rangos grandes de tiempo, por lo tanto tener hasta el ultimo segundo, no suele ser relevante para ellos.

En principio, podemos asumir que vamos a diseñar las tablas en el Data Lake, como si fuera un Data Warehouse (DW), pero esto no quiere decir que el Data Lake entero va a estar compuesto de varios DW. Es una buena idea crear un DW cuando necesitamos el histórico de ciertos valores, en general los que se representan en las dimensiones de un modelo estrella o cuando tenemos una serie de métricas que se pueden agregar en base a algún parámetro. Por ejemplo, si queremos saber el histórico completo de lo que se facturo para un cliente por día en un rango de fechas, el modelo estrella es un excelente modelo para esto. Ecosistemas hechos en Hadoop, tienen herramientas como Hive que son ideales para esto. En un DW, no necesitamos hacer updates excepto en algunos valores en las dimensiones (y dependiendo el tipo de dimensión), pero en la tabla de hechos que es la mas grande y la mas consultada, solo se corren INSERTS (o quizás algún DELETE de vez en cuando).

Hay otras fuentes de datos que quizás no convenga esforzarse por insertar en formato estrella. Supongamos que tenemos un proyecto de “Internet of Things” (IOT) en donde tenemos una serie de artefactos que insertan registros de manera continua. Tener simplemente una tabla donde se loguean todos los eventos con sus descripciones, etc, quizás sea lo mejor para leer e insertar rápido en la misma. Si están trabajando sobre Hadoop, recuerden que necesitan un proceso batch que corra periódicamente para extraer la información. Esto quiere decir que van a necesitar “algo” que funcione como buffer. Si necesitan insertar y consultar la información en vivo (por ejemplo para un sistema de monitoreo en vivo), quizás una tecnología como Cassandra sea mucho mas útil para el caso.

Por otro lado, el caso mas complejo que me encontré hasta ahora fue el siguiente: Mi cliente tenia dos bases de datos relacionales grandes que se ocupaban de dos áreas del negocio que eran fundamentales para ellos. Dando un poco de contexto, mi cliente ofrece tarjetas de crédito. Un área se ocupaba de lo que seria “adquisición de nuevos clientes” y la otra de “datos sobre clientes actuales”. Por diversos motivos, mi cliente pidió distintas columnas que estaban relacionadas de muchas maneras distintas entre si en estas bases relacionales. En este caso, trate de encarar el problema por el lado de encontrar las entidades que eran principales dentro de cada sistema. Todas las bases de datos tienen tablas que son más importantes que otras en términos del negocio. Lo que hice luego, fue desnormalizar los datos que estaban referenciados a estas tablas y recrear estas mismas en mi Data Lake con todos sus atributos dentro (en otras palabras sin ids con FK). Si bien esto no le permite a mi cliente ver el histórico completo (haría un DW para eso), les permite de manera fácil, ver el estado actual de cada área del negocio. Entonces, lo que queda, son entidades principales con todos sus valores dentro con los identificadores que las relaciona entre si. Esto le permite a mi cliente correr un reporte diario con el estado del negocio a la mañana antes que todos sus empleados entren a trabajar en poco tiempo. El problema, es obviamente el procesamiento y actualización de estos datos periódicamente.

Por ahora esto parece suficiente. Acepto cualquier tipo de crítica o sugerencia respecto a los temas expuestos y desde ya le agradezco por cualquier sugerencia que puedan aportarme.

Saludos,

Alejandro

 

Oracle: Error INS 30131 durante la instalación

Estuve peleando con este error un tiempo largo, así que lo voy a dejar documentado acá. Primero un poco de contexto: estaba intentando instalar los clientes de Oracle en una virtual con Windows 10 ya que mi querido cliente del exterior, decidió eliminar mi vieja virtual con todo corriendo y darme una nueva con 3 días de aviso.

Dejando de lado las quejas, parece que el error sucede cuando intentamos instalar ambos servicios de 32 y 64 bits. Probé todo lo que estaba en internet, desde registrar la dll instalada, probar distintos instaladores y hasta hacer al usuario que instala admin del “C:”. Nada de eso funciona. Lo que sí funciona y como siempre tiene que ver en estos casos con algo de Oracle, parece que Oracle cuando instala, levanta un servicio que se llama “OracleRemExecServiceV2”. La recomendación de todos, es parar el servicio, pero resulta que en mi caso, no me dejaba hacerlo.

Insistiendo y buscando un poco más, encontré que el problema estaba en los registros del sistema. Usando “regedit” en inicio de windows, podemos ver las mismas. Luego, tuve que buscar: \HKEY_LOCAL_MACHINE\SOFTWARE\ORACLE\oracleremexecservicev2\. Entre las key, van a ver una que tiene un path a donde se supone que corre el servicio. En mi caso, este valor estaba mal! Directamente no existía la carpeta indicada, por lo tanto la cambie a la carpeta correcta. Por suerte, el path estaba mal, pero tenia algo similar. Por ejemplo en vez de decir “…\asemprini\…” decia “\ASEMP~1\”.

Lo corregí, reinicie la pc, y el servicio simplemente desapareció. Despues de eso pude correr el instalador siguiente de Oracle que correspondía.

Saludos,

Alejandro

SSIS: Extraer datos de Oracle sin Attunity

Hola, ultimamente vengo trabajando bastante con bases relacionales en Oracle, por lo tanto hoy voy a subir la forma en la que me estoy conectando a ellas. Empezemos por decir que el “Microsoft OLE DB Provider for Oracle” esta deprecado y no es recomendale utilizarlo:oleDbProviderDeprecated

Lo que si podemos utilizar, es el provider que Oracle nos provee para esta tarea. El mismo, lo podemos encontrar en este link (varia segun la version de Oracle):  http://www.oracle.com/technetwork/database/enterprise-edition/downloads/oracle12c-windows-3633015.html

Acepten la licencia de Oracle y vayan hacia abajo hasta encontrar los “Oracle Clients” como en la siguiente imagen:

Oracle clients

Es altamente probable que necesiten ambos. Visual Studio y SQL Server, todavía son bastante problemáticos con las versiones de 32 o 64 bits. Descarguen los dos, y recuerden que necesitan una cuenta en Oracle para hacerlo, si no la tienen, creen una.

Una vez descargados, descomprimanlos (deberían ser archivos “.zip”) y corran el setup.exe (como administradores). Luego, elijan la opción Runtime. Esta opción instala todo lo que puedan llegar a necesitar para conectarse a Oracle sea cual sea la herramienta que estén usando para hacerlo.

OracleClient

Sigan el instalador, y elijan el path en donde se va a instalar el cliente. Por default, siempre se usa el path C:\Oracle como principal.

El tnsnames.ora, si no les aparece, deben crearlo con las conexiones a los servidores como corresponde. En mi caso, el tnsnames.ora tiene que estar en C:\Oracle\product\12.2.0\client_1\network\admin\. Si necesitan un tnsnames.ora de ejemplo, pueden encontrar uno que crea el instalador. En mi caso, se encuentra en C:\Oracle\product\12.2.0\client_1\network\sample\.

Una vez instalado esto, no deberían tener problemas para conectarse desde Visual Studio o SQL Server. Recuerden usar el “Oracle Provider” y no el “Microsoft Ole db Provider”.

Saludos!

 

 

PowerShell: Correr un job de SQL Server Agent y ver su progreso

Por distintas cuestiones, estoy en un proyecto donde no puedo simplemente poner algo a correr desde el SQL Agent. El cliente tiene una herramienta que puede monitorear tareas programadas desde el Windows Scheduler pero no desde el SQL Server Agent. Si bien mi proyecto se trata de crear paquetes de SSIS que simplemente podría ejecutar con un dtexec dejando los paquetes en una carpeta, la verdad es que no quiero perder todos los beneficios de utilizar el “Proyect deployment model” de SSIS. Por lo tanto voy a poner los paquetes en el SSIS catalog, crear los jobs en el SQL Server Agent y correr los jobs desde PowerShell.

Primero cree un job de prueba “1_test” que tenia los siguientes pasos:

  1. Correr una consulta
  2. Hacer un WAITFOR DELAY ’00:02:00′

Luego, utilice el siguiente script que lo encontre en este link.

#param ( [string]$ServerName,[string]$JobName,[string]$StepName )

[string] $ServerName = "servidor"
[string] $JobName = "1_test"

write-host "Starting SQL Agent Job $($JobName) on Server $($ServerName)"
#write-host "JobName $($JobName)"
$date=Get-Date
write-host "It is now: $($date)"

[System.Reflection.Assembly]::LoadWithPartialName('Microsoft.SqlServer.SMO') | out-null

$srv = New-Object Microsoft.SqlServer.Management.SMO.Server("$ServerName")
$job = $srv.jobserver.jobs["1_test"] 

$jobstart="No" 

if (($job))
{
   $job.Start()
   $jobstart="Yes"
   Start-Sleep -s 5  # Pause for 5 seconds (optional) - was 30 seconds (v1); v2=5
}
else
   {
        $jobstart="Not found"
   }
if ($jobstart -eq "Yes")
  {
  write-host "Job $($JobName) on Server $($ServerName) started"
  $i=0
  do
   {
    $job.Refresh();
    $iRem = $i % 5;
        $jobrunning=$job.CurrentRunStatus.ToString();
        if ($iRem -eq 0)
           {
           $date=Get-Date
           write-host "Job $($JobName) Processing--Run Step:$($job.CurrentRunStep) Status:$($job.CurrentRunStatus.ToString())... at $($date)"
           } 

    Start-Sleep -s 10;  # Pause for 10 seconds  - was 60 seconds (v1); v2=10
        $i++;
  }
  while ($job.CurrentRunStatus.ToString() -ne "Idle")
  if ($job.LastRunOutcome -ne "Cancelled")
    {write-host "Job Processing done"}
  else
    {write-host "Job Processing cancelled/aborted"}
   #   $jobrunning="TRUE"
       write-host "$($srv.name) $($job.name)"
           write-host "Last job outcome $($job.LastRunOutcome)"
           write-host "Last job outcome $($job.LastRunDate)"
           $l = $job.LastRunDate
           $p=$job.LastRunOutcome
           $q=$job.LastRunOutcome
           $x = $job.EnumHistory()
           $y = $job.EnumHistory().Rows

           if ($job.EnumHistory().Rows[0] -ne $null)
            {
                write-host "xxxx $($job.EnumHistory().Rows[0].Message)"
                }
                if ($job.EnumHistory().Rows[1] -ne $null)
                  {
                   write-host "yyyyy $($job.EnumHistory().Rows[1].Message)"
                  }
                  $z = $job.JobSteps.Count - 1
                  for ($i=0;$i -le $z;$i++)
                   {
                    $m = $job.JobSteps[$i].LastRunDate
                        write-host "Name: $($job.JobSteps[$i].Name) RunDate: $($job.JobSteps[$i].LastRunDate) Status: $($job.JobSteps[$i].LastRunOutCome)"

                     if ($l -gt $m)
                          {
                            $p="FailedOrAborted"
                          }
                   } 

  if ($p -eq "Failed")
    {
        write-host "Job returned with Failed status"
          exit 2
    } 

  if ($p -ne "FailedOrAborted")
    {
        if ($p -ne "Cancelled")
        {exit 0}
        else
        {
          write-host "Job Cancelled xxxxx"
          exit 3
        }
        }
  else
    {
        write-host "Job Failed or Aborted"
        exit 2
        }
  }
  else
  {
  write-host "Unable to Start Job $($JobName) on Server $($ServerName)"
  write-host "Reason: Job may not exist or not enabled."
  exit 1
  }

Con esto ahora puedo tener todos los beneficios de poner mis paquetes dentro del Catalog de SQL Server y además le permito al cliente monitorear los jobs.

Saludos,
Alejandro

SSIS: Dividir una fuente de datos en base a una condición

A veces logro responder preguntas en StackOverflow antes de que alguien más lo haga y en este caso había una consulta que decía “¿Como incrementar por mes en SSIS?”. Más allá de que esto era posible con un Loop y una variable, se me ocurrió preguntarme por qué esta persona había decidido hacerlo de esta forma y no dejar que simplemente SSIS se ocupara de manejar el batch de datos.

Más que decirle como hacer lo que quería hacer, le respondí lo que me parecía más lógico que era tomar la fuente, agregar un split por mes y crear un destino por cada archivo que quisiera generar.

La forma de hacer lo anterior es la siguiente:

  1. Se crea una conexión a la base de datos donde vamos a extraer los datos
  2. Se agrega un Data Flow Task
  3. Se agrega un OLE DB Data Source con la query que te traiga un año de datos
  4. Agregar un “Conditional Split” de SSIS.
  5. Agregar las expresiones según sea necesario.Split.PNG
  6. Agregar las fuentes de destino y una flecha en el dataflow por cada mes.Split2.PNG

NOTA: No es necesario que los archivos existan para correr el proceso. Se le especifica a la tarea que cree los mismos cuando ejecuta. Si luego necesitan mover los archivos, pueden hacerlo fuera del DataFlow.

Si su servidor tiene los recursos suficientes, esto debería ser mas performante que un loop por cada mes del resultado. En vez de serializar la creación de archivos con su respectiva información, se paraleliza y se deja que SSIS maneje la carga de trabajo.

Saludos,
Alejandro

link SO: https://stackoverflow.com/questions/42583120/how-to-increment-by-month-in-an-ssis-package/42584904#42584904

T-SQL: Mostrar X registros

Apareció esta búsqueda entre los motivos por los cuales algunos visitaron la página por lo tanto decidí responderla. En SQL Server es bastante fácil. Lo único que hay que hacer es usar la sentencia TOP:

SELECT TOP 10 * FROM tabla

Esto significa que la consulta solo me va a mostrar los primeros 10 registros que encuentre. Otra característica del TOP es que el valor o la cantidad de registros a traer es parametrizable por lo que podríamos hacer el número variable (aunque sinceramente nunca tuve la necesidad de hacerlo).

Para otros motores de base de datos la respuesta varía. Les recomiendo el siguiente link: http://www.w3schools.com/sql/sql_top.asp.

Saludos!