Oasis

lunes, julio 10, 2006

sp_OAGetErrorInfo


Hoy me tope con un problema que me parece que merece la pena ser publicado, el caso es que existen varios Store Procedures en una de las aplicaciones a las que les doy soporte, los cuales lanzan DTS.

Cuando empiezo a revisar el problema, lo primero que me imagine fue que el SP no corrió, pero no fue así, el SP si se ejecuto, entonces me fui a la parte donde se ejecuta el dichoso DTS ya que es la parte medular del proceso, debido a que sin DTS no hay datos y sin datos no se reflejan resultados y precisamente eso fue lo que reporto el usuario.

Bueno, al principio no tenia idea de que pasaba, ejecutaba el código para lanzar el DTS y solo recibía mensajes que yo los había puesto. Voy a poner el código para verlo mejor.

EXEC @hr = sp_OACreate 'DTS.Package', @oPKG OUTPUT -- Create Package
EXEC @hr = sp_OAMethod @oPKG, 'LoadFromSQLServer("SERVER", "USER", "PWD", 0, , , , "DTSNAME")', NULL
if ( @hr <> 0 )
begin
print ' Error in Loading Package '
end

EXEC @hr = sp_OAMethod @oPKG, 'Execute'
if ( @hr <> 0 )
begin
print ' Error in Executing Package '
end

EXEC @hr = sp_OAMethod @oPKG, 'UnInitialize'
EXEC @hr = sp_OADestroy @oPKG

Como vemos solo me salía Error in Loading Package y Error in Executing Package, con esto pues no podía llegar a ningún lado, así que puse un print para ver el valor de @hr. Eso no me ayudo en absolutamente nada, así que empecé a investigar los métodos sp_OACreate, sp_OAMethod y me encontré con uno que estaba omitiendo y que es de gran ayuda, este es
sp_OAGetErrorInfo.

Con este saque cual era el problema, substituyes esos mensajes de error que puse por esos que te genera este comando y listo, ahora si tenemos un mensaje de error real.

Este seria un ejemplo:

EXEC sp_OAGetErrorInfo @oPKG, @errorSource OUTPUT, @errorDescription OUTPUT

SELECT [Error Source] = @errorSource, [Description] = @errorDescription


Aquí dejo el código completo:

DECLARE @hr int, @oPKG int
DECLARE @errorSource NVARCHAR(1000), @errorDescription NVARCHAR(1000)

EXEC @hr = sp_OACreate 'DTS.Package', @oPKG OUTPUT -- Create Package
EXEC @hr = sp_OAMethod @oPKG, 'LoadFromSQLServer("SERVER", "USER", "PWD", 0, , , , "DTS")', NULL
if ( @hr <> 0 ) begin
EXEC sp_OAGetErrorInfo @oPKG, @errorSource OUTPUT, @errorDescription OUTPUT
SELECT [Error Source] = @errorSource, [Description] = @errorDescription
end

EXEC @hr = sp_OAMethod @oPKG, 'Execute'
if ( @hr <> 0 ) begin
EXEC sp_OAGetErrorInfo @oPKG, @errorSource OUTPUT, @errorDescription OUTPUT
SELECT [Error Source] = @errorSource, [Description] = @errorDescription

end

EXEC @hr = sp_OAMethod @oPKG, 'UnInitialize'
EXEC @hr = sp_OADestroy @oPKG

lunes, febrero 27, 2006

SQL: Optimización de las consultas

Bueno, ya tenemos la forma en la cual podemos capturar o rastrear los eventos que se están ejecutando en el servidor, ahora es importante saber leer estos eventos y saber cuales están provocando un stress o demora en el desempeño.

Normalmente lo que pasa cuando el desempeño esta mal son 2 cosas:


• Estas consultas consumen muchos recursos del sistema y hacen que no se realice un desempeño adecuado.
• También pasa que las consultas problemáticas bloquean a otras consultas haciéndolas lentas, por lo tanto optimizar a las consultas problemáticas beneficia a todas las consultas y eventos.

Para identificar a estas consultas lentas o problemáticas podemos usar las columnas CPU o Reads. Como ya sabemos Read es el numero de lecturas y CPU el numero de milisegundos que tarda una consulta.

Aunque un evento solamente haga lecturas hace una especie de bloqueo sobre los datos, por lo tanto es importante optimizarlos.
Hay 2 categorías de consultas problemáticas:
• Simples
• Múltiples


Las simples las identificamos porque tienen una cantidad grande en la columna “reads”, es decir una sola consulta es muy robusta en sus lecturas.
Las múltiples las identificamos porque son pequeñas consultas que se ejecutan muchas veces, es decir consultas con “reads” pequeños pero ejecutados con mucha frecuencia.

martes, febrero 21, 2006

SQL Profiler: Recomendaciones para el Trace

Recomendaciones del libro que estoy leyendo ( “SQL Server Query Performance Tuning Distilled, Second Edition by Sajal Dam” ).
  1. Limitar el numero de eventos y columnas: Se utiliza la PRE y POST filtración, esto es importante ya que de lo contrario estaríamos utilizando muchos recursos. Prefiltrar es estar viendo al momento las actividades capturadas y postfiltrar es donde analizas lo capturado.
  2. Sacar los eventos Start. Nos dicen que no los necesitamos puesto que lo que queremos es ver resultados cuando se terminan de ejecutar los procesos, ahí es cuando tendremos resultados de la duración, costos, etc.
  3. Limitar el tamaño del rastreo: Se nos recomienda poner en propiedades la Duración y las lecturas > 2 ya que las menores no son muy optimizables.
  4. Evitar ordenamientos al momento de hacer el rastreo. Es preferible hacer este ordenamiento una vez que se termine de ejecutar el trace, lo que debemos de hacer es grabarlo y entonces si, aplicar los ordenamientos y agrupaciones que queramos.
  5. No Ejecutar el profiler remotamente. Nos dice que no esta bien ejecutar herramientas de pruebas en el servidor de producción, esto porque el profiler no corre por una sesión remota, y además porque los resultados los dejaría en un directorio del Server y no de nuestra PC.
  6. Capturar el rastreo utilizando Procedimientos Almacenados. Es recomendable hacer el rastreo con un procedimiento almacenado ya que es mas ligero. Lo malo de esto es que es tardado crear el script de este store procedure, porque se necesitan los siguientes comandos:
  • sp_trace_create: Creamos el rastreo.
  • sp_trace_setevent: Agregamos eventos y columnas.
  • sp_trace_setfilter: Aplicamos filtros.
  • sp_trace_setstatus: Iniciamos el rastreo.

    Para evitar hacer el script se nos recomienda lo siguiente:
  • Abrir el profiler
  • Conectarnos al servidor.
  • Abrir un templete ya existente o bien definir uno nuevo.
  • Correr el trace ( temporalmente )
  • Parar el trace.
  • Crear un SQL Script de este trace o rastreo.
  • Abrir este Script en el Query Analyzer.
  • Modificar el parámetro “InsertFileNameHere” del comando sp_trace_create
    Ejecutar el Script, con esto comercia el trace, nos dara un ID ( traceid ) que lo usas para detener el trace.

    Para detener el trace podemos ejecutar el siguiente codigo: EXEC sp_trace_setstatus 1, 0 despues de esto debemos de cerar y borrar el trace, esto se hace con el siguiente codigo:
    sp_trace_setstatus 1, 2

lunes, febrero 20, 2006

SQL: Data Columns y Filtros del trace

Continuando con el profiler, esta herramienta nos permite seleccionar que columnas de datos queremos visualizar, estas columnas representan diferentes atributos de un evento, las columnas que utilizaríamos serian al menos las siguientes:

  • EventClass ( Tipo de Evento )
  • TextData ( Operación ejecutada )
  • CPU ( Costo en milisegundos del CPU )
  • Reads ( Numero de lecturas )
  • Writes ( Numero de escrituras )
  • Duration ( Tiempo de ejecución en milisegundos )
  • SPID ( Identificador del proceso )
  • StartTime ( Tiempo de arranque ).

Estas columnas las podemos especificar dentro de la herramienta en la pestaña de Data Columns. Además de las ya mencionadas columnas existen muchas mas que pueden ser de gran ayuda, unas de las que me llamaron la atención para agregarlas son las de:

  • EventSubClass
  • DatabaseID
  • IndexId
  • Error
  • TransactionID.

También es conveniente ponerle filtros a nuestro rastreo ya que no es necesario tener todo lo que se esta ejecutando, sino solo lo que esta entorpeciendo el desempeño de la base de datos. Podemos filtrar los eventos para solo tener los que se presentan en la aplicación y base de datos que queremos, para los eventos que duran mucho ( poner mayor a 2 ), para los que realizan muchas lecturas y talvez de algún usuario en especial.

miércoles, febrero 15, 2006

SQL: Que podemos hacer con el SQL Profiler.

  • Esta herramienta nos sirve para Monitorear las actividades del servidor SQL, analisis de rendimiento, Diagnosticar problemas, etc. Tambien se pueden capturar las actividades desarrolladas en el server, esto se hace con el "TRACE".
  • Este trace tiene diferentes eventos, entre los cuales tenemos eventos por cursores, Procedimentos almacenados, por locks y consultas, cada evento tiene una descripcion que nos va a ayudar en este caso para realizar un analisis de desempeño y realizar acciones correctivas si es necesario.
  • El analisis del desempeño se realiza una vez que los eventos terminan, los eventos que me van a servir a mi son de Store Procedures ( RPC y Stmt ) y TSQL. Los RPC son procesos que son ejecutados usando Remote Procedure Call, esto se ejecuta por el driver ODBC y son ejecutadas mas rapido que si ponemos un EXEC en una sentencia TSQL. Los Stmt son sentencias de SQL dentro de un Store Procedure, esto puede ser un SELECT COUNT(Emp_ID) FROM Empleados.
  • Bueno ya sabemos de algunos de los eventos que necesitamos, pero como capturar estos eventos?, como tener solamente los que queremos ver?, puesto que el Profiler tiene una lista de eventos muy grande, pues es muy sencillo, en el Profiler viene una pestaña que tiene el listado de los eventos y ahi los añadimos y removemos.

  • Como dije anteriormente, solo sabemos de algunos eventos, existen aun mas, voy a poner una lista que viene en el libro que estoy tomando como referencia para todo esto.



Bueno, falta muchisimo que leer, seguire leyendo y conforme tenga mas conocimientos del tema los ire escribiendo aqui.

SQL Profiler: Trace

En el trabajo se esta presentando un problema que al principio no existia, este problema es que se estan generando excepciones de "time-out", para no darle tantas vueltas a las cosas ire al grano. Me comento Carlos Madrigal que podemos utilizar el Trace que trae la herramienta SQL Profiler para poder hacer un rastreo de las excepciones, y ver cuales son los procesos que estan causando estos bloqueos.

Tambien me recomendo un Libro "SQL Server Query Performance Tuning Distilled, Second Edition by Sajal Dam".

Voy a empezar a leerlo y estare escribiendo mis avances.

viernes, enero 27, 2006

Upps

Ya encontre una forma mas facil para hacer lo que comentaba en el tema del REPLICATE, como dice ahi lo que necesitabamos era tomar el año y el mes de una variable tipo fecha (YYYYMM).

Sencillamente esto se resuelve asi:
convert(char(6), sInv_LoadDate, 112)

donde sInv_LoadDate es una variable tipo fecha.


Lo que nos paso fue que corrimos el query asi:
convert(char(6), '1/25/2005 10:00:00 PM', 112)

y pues nos dio este resultado: '1/25/2'

Por eso pensamos que no funcionaba, buscamos otra solucion, etc, etc .


El punto es que lo debimos hacer con la variable tipo fecha y no con la cadena.

SQL: Replicate

Hace unos dias, resolviendo un problema que traiamos en el trabajo usamos la funcion REPLICATE. Lo que pasaba era que de una fecha necesitabamos solamente el año y el mes ( YYYYMM ), esto porque el reporte era por periodos. Buenos, entonces dijimos hay que sacar el año y el mes y los concatenamos no???

Pero la funcion MONTH() regresa un int, asi que :

1) Si hacemos esto:
SELECT YEAR('1/30/2005 5:40:58 PM') + MONTH('1/30/2005 5:40:58 PM')

Lo que pasa es que nos suma 2005 + 1 = 2006 y pues claro, esto no es lo que buscamos.

2) Entonces pensamos, hay que convertirlas a char:
SELECT CAST(YEAR('1/30/2005 5:40:58 PM') AS CHAR(4)) + CAST(MONTH('1/30/2005 5:40:58 PM') AS CHAR(2))

Pero ahi nos topamos con otro problema, nos regreso '20051' debido a que la funcion MONTH() solo regreso un '1' y no un '01' como hubieramos deseado ('200501').

Entonces recorde que habia buscado una vez una funcion para ponerle ceros a la izquierda a unos cheques, pero no me acordaba ni cual era ni donde la habia usado, asi que tarde buen rato buscando hasta que la encontre.

3) Usamos el REPLICATE() para ponerle un cero a la izquierda al mes y concatenarlo:
SELECT CAST(YEAR('1/30/2005 5:40:58 PM') AS CHAR(4)) + REPLICATE('0',2-LEN(CAST(MONTH('1/30/2005 5:40:58 PM') AS CHAR(2))))+ CAST(MONTH('1/30/2005 5:40:58 PM') AS CHAR(2))

pero, porque puse ese 2- tan grandote? Ah pues porque es muy importante que lo pongamos ya que ahi estamos diciendole el tamaño de longitud de la cadena. Es que el replicate lo que hace es repetir una cadena el numero de veces que tu le digas, por lo tanto lo que hicimos fue repetir el cero 1 vez ( 2 - 1).

2-1? Si, el 2 yo lo puse y el 1 sale de la longitud del mes, osea 1. Y que pasaria con meses de 2 digitos? pues 2-LEN(MONTH('11/30/2005 5:40:58 PM')) es 2-0 = 0, y pues no pondra ningun cero y solo concatenaremos el mes de dos digitos.


Bueno el punto es que el REPLICATE() repite cadenas las veces que le digas y si necesitas ponerle ceros a la izquierda a alguna cadena pues asi lo puedes hacer.

Otro ejempo:
SELECT REPLICATE('0', 10-LEN(270)) + CAST(270 AS CHAR(10))

jueves, enero 26, 2006

Inicio

El dia de hoy me anime a crear un blog, en este voy a ir metiendo vivencias que vaya teniendo ( Dentro del area de Sistemas Computacionales ).
Hasta hace pocos dias tenia la idea que un Blog era para personas con muchisima sabiduria, gente que realmente aporta conocimientos y pues me dije "Yo que voy a aportar?", pero pues ese no es el unico proposito, esto ayuda en muchisimas cosas mas, principalmente al que los escribe.
Asi pues, aqui voy ir escribiendo algunas cosas que vaya aplicando en mi trabajo y lo que vaya aprendiendo de lecturas que vaya haciendo.