martes, 21 de diciembre de 2010

Liberado el CU5 de SQL Server 2008 R2 RTM

Ha sido liberado el pack acumulativo 5 de actualizaciones para SQL Server 2008 R2 RTM.

Aqui podeis encontrar información sobre los fixes que se realizan: http://support.microsoft.com/kb/2438347/en-us 

Para más información ir a la fuente:

http://blogs.msdn.com/b/sqlreleaseservices/archive/2010/12/20/cumulative-update-5-for-sql-server-2008-r2-rtm.aspx?utm_source=twitterfeed&utm_medium=twitter&utm_content=%23release

Automatiza el análisis de contadores de rendimiento

Como bien sabe cualquier DBA, siempre conviene ser proactivo y parte de esa proactividad es la capacidad de analizar la información que proviene de nuestros sistemas de la forma mas útil posible.

En este caso me he decidido a escribir brevemente sobre un apartado que mucha gente no conoce del colector de contadores de rendimiento, su capacidad de almacenar la información en base de datos.

Si bien no quiero llevaros a pensar que es la práctica a seguir siempre (cada escenario es diferente), si quiero daros a conocer las posibilidades que tenemos de utilizar este enfoque, dado que es muy versatil.

Lo único que necesitamos es crearnos un DSN de sistema, que apuntaremos a la instancia y BBBDD donde queramos almacenar la información.

Para ello lo voy a enseñar con una serie de screenshots, que se ve claro:

1. Abrimos el administrador de origenes de datos ODBC y nos vamos a la pestaña “System DSN

image

Figura 1

2. Seleccionamos el driver “SQL Server”

image

Figura 2

3. Configuramos su conexión como vemos en las figuras de la 3 a la 7. Nótese que debemos especificar una BBDD donde almacenar la información.

     La BBDD que pongamos, si no tiene las tablas donde almacenarse la información, en el proceso de configuración del colector de datos se creará. Si ya existian por el contrario, no se borrarán, se insertarán los datos sin más.

image

Figura 3

imageimage

Figura 4-5

imageimage

Figuras 6-7

4. Una vez hemos acabado de configurar nuestro DSN de sistema, procedemos ahora a configurar el colector de datos. Para ello abrimos el monitor de rendimiento (ver figura 8)

image

Figura 8

5. Nos vamos a definirnos un colector de usuario como se puede apreciar en las figuras 9 a la 12

imageimage

Figuras 9-10

NOTA: En la figura 12 nos pide una ruta de disco local donde almacenar la información. Puesto que por defecto se crea así, le especificaremos una ruta, pero no será utilizada por lo que podemos dejarla como está

imageimage

Figuras 11-12

6. Ahora es cuando realmente hacemos la parte “diferente” del proceso, puesto que configuraremos el colector para que en lugar de almacenar la información en formato binario en la ruta especificada anteriormente, le diremos que lo almacenaremos en base de datos, utilizando el DSN de sistema creado con anterioridad

 

image

Figura 13

Al pulsar sobre propiedades tal como se aprecia en la figura 13, pasamos a configurar el “log format”  indicando que lo deseamos en formato SQL (figura 14) y posteriormente indicamos el DSN de sistema que utilizará para almacenar la información (figura 15).

imageimage

Figuras 14-15

7. Una vez pulsado en el botón de inicio de coleccionar datos, se procederá a la creación de objetos necesarios para ello en la BBDD destino

image

Figura 16

image

Figura 17

NOTA: Fíjese como ahora el Output es SQL:loquesea. Esto en otras configuraciones es una ruta a un fichero .blg

8. La última parte ya corre de vuestro lado. Quedaria por tanto explotar esa información (como podeis ver por ejemplo en el Code Snippet que os he dejado), reciclar la información, crear reportes, consolidar,…

Code Snippet
  1. SELECT
  2.   dtid.DISPLAYSTRING
  3.             , cd.MACHINENAME
  4.   , cd.OBJECTNAME
  5. , cd.COUNTERNAME
  6. , cd.INSTANCENAME
  7. , cdta.COUNTERDATETIME
  8. , cdta.COUNTERVALUE
  9. FROM dbo.CounterData AS cdta
  10.          INNER JOIN dbo.CounterDetails AS cd ON cdta.COUNTERID = cd.COUNTERID
  11.          INNER JOIN dbo.DisplayToID AS dtid  ON cdta.GUID = dtid.GUID

image

Figura 18

Espero haberos dejado un buen punto de partida para “juguetear” Smile

Salu2!

miércoles, 15 de diciembre de 2010

Analizar automáticamente los resultados de SSUA

Uno de los principales procesos a seguir cuando se planea la migración de SQL Server hacia una versión superior del motor es la de analizar los potenciales problemas de incompatibilidad entre versiones.

Actualmente, se viene percibiendo en el mercado una gran cantidad de proyectos de migración desde versiones de SQL Server 2000 hacia SQL Server 2008 y 2008 R2. Dichos proyectos, principalmente vienen motivados tanto por la gran cantidad de mejoras y características que vienen de serie con las últimas versiones del motor, como de la necesidad de actualización debida a la pérdida de soporte de SQL Server 2000 por parte de Microsoft (http://support.microsoft.com/lifecycle/?p1=2852)

Debido a esta circunstancia, no solo el número de proyectos de migración se incrementa, sino que el número de instancias y bases de datos a migrar se multiplica (por experiencia encuentro que típicamente se tienen más de 3 instancias de SQL Server, con 10 BBDD cada una de media). Debido a esta circunstancia, al realizar assesments de migración hacia SQL Server 2008 y 2008 R2, debemos manejar mucha información.

En Solid Quality Mentors, hemos desarrollado una herramienta que hemos denominado HealthCheck y sobre la que hablaremos desde esta revista asiduamente, con la que entre otras cosas, facilitamos el trabajo con los ficheros de resultados de SSUA.

¿Qué es SSUA (Sql Server Upgrade Advisor)?

Es una herramienta gratuita proporcionada por Microsoft, para realizar labores de detección de patrones T-SQL y configuraciones depreciadas de SQL Server. Con ella, podremos saber si en cualquier objeto de nuestra base de datos existe una construcción sintáctica T-SQL depreciada que no funcionará en la versión del motor a la que deseamos migrar.

¿Por qué deseamos una automatización de los resultados de SSUA?

Como he avanzado al principio del artículo, una migración típica involucra más de una instancia de SQL Server, es por ello que en ocasiones analizar los resultados puede resultar una tarea tediosa.

¿Qué pretendemos automatizar?

La idea, es generar un fichero que contenga una línea por objeto a modificar, con información extra que con nuestra propia experiencia en la materia nos ayude a identificar lo que es costoso de lo que no, para que de un vistazo rápido, podamos realizar una valoración objetiva lo más acercada a la realidad, de lo que el coste del proyecto final nos puede suponer.

En la imagen siguiente, se puede apreciar como la forma de presentar los resultados por parte de SSUA aunque acertada, no es todo lo útil que desearíamos cuando tenemos que lidiar con múltiples objetos y/o ficheros de resultado.

clip_image002

No obstante, SSUA nos ofrece la posibilidad de exportar la información a un fichero .csv

clip_image004

Cuyo resultado es como el siguiente (después de procesarlo introduciendo sus valores en celdas):

clip_image006

La parte buena es que como se puede apreciar, aparece información de forma tabular. La parte no tan buena es que sigue sin ser completamente controlada por nosotros (“Database name: master”, por ejemplo no es óptimo porque sobraría “Database name:”).

La idea por tanto es que de una manera fácil y sencilla, haciendo uso de las características inherentes de Visual Studio y .net 4.0, podamos operar con los XML resultado de una forma exitosa y fácil.

Procesamiento del documento XML

La idea que me gustaría ilustrar, es que podemos procesar los resultados de SSUA de una forma cómoda y rápida usando Visual Studio 2010. Para ello, una vez obtenida la información con SSUA (resultados típicamente obtenidos bajo la ruta “\Documents\SQL Server 2008 Upgrade Advisor Reports”), procedemos a crearnos un esquema .xsd del documento XML con los resultados deseados ( DE.xml por ejemplo, es el que contendrá los resultados del motor relacional).

Abrimos el documento desde Visual Studio 2010 y seguidamente nos vamos a las opciones de menú XML->Create Schema

clip_image007

Una vez pulsado ahí, obtendremos su esquema .xsd

clip_image009

Como vemos, nada nuevo. La gracia viene ahora.

Podemos crearnos un proyecto de Visual Studio, al que añadir el siguiente código:

Code Snippet
  1.         public static DataTable Analyze(string pathToXml)
  2.         {
  3.             FillIssueTimming();
  4.             DataSet ds = new DataSet();
  5.             ds.ReadXmlSchema("SSUA\\XMLSchemas\\DE.xsd");
  6.             ds.EnforceConstraints = false;
  7.             XmlDataDocument xml = new XmlDataDocument(ds);
  8.             xml.Load(pathToXml);
  9.             var query = from ia in ds.Tables["ItemAttribute"].AsEnumerable()
  10.                         join ias in ds.Tables["ItemAttributes"].AsEnumerable()
  11.                             on ia.Field<int>("ItemAttributes_id") equals ias.Field<int>("ItemAttributes_id")
  12.                         join item in ds.Tables["Item"].AsEnumerable()
  13.                              on ias.Field<int>("Item_id") equals item.Field<int>("Item_id")
  14.                         join r in ds.Tables["Report"].AsEnumerable()
  15.                             on item.Field<Nullable<byte>>("ItemId") equals r.Field<Nullable<byte>>("ItemId")
  16.                         join iss in ds.Tables["Issue"].AsEnumerable()
  17.                             on r.Field<Nullable<byte>>("IssueId") equals iss.Field<Nullable<byte>>("IssueId")
  18.                         select new
  19.                         {
  20.                             ItemAttributesId = ia.Field<int>("ItemAttributes_id"),
  21.                             Name = ia.Field<string>("Name"),
  22.                             Value = ia.Field<string>("Value"),
  23.                             Issue = iss.Field<string>("IssueDescription"),
  24.                             IssueText = iss.Field<string>("IssueText"),
  25.                             IssueType = iss.Field<string>("IssueType")
  26.                         };
  27.  
  28.           // Get all the info you want in the export file
  29.           //
  30. DataTable resultado = new DataTable("results");
  31.             resultado.Columns.Add("IssueId", typeof(int));
  32.             resultado.Columns.Add("IssueType", typeof(string));
  33.             resultado.Columns.Add("Source Type", typeof(string));
  34.             resultado.Columns.Add("Database Name", typeof(String));
  35.             resultado.Columns.Add("Object Name", typeof(String));
  36.             resultado.Columns.Add("Object Type", typeof(String));            
  37.             resultado.Columns.Add("Keyword", typeof(String));
  38.             resultado.Columns.Add("Issue", typeof(String));
  39.             resultado.Columns.Add("SQL Batch", typeof(string));
  40.             resultado.Columns.Add("Trace File", typeof(string));
  41.             resultado.Columns.Add("IssueText", typeof(String));
  42.             resultado.Columns.Add("Estimated time of adaptation", typeof(String));
  43.             resultado.Columns.Add("Comments", typeof(String));
  44.  
  45.    foreach(var row in query)
  46.             {
  47.                 if (issueid_old != row.ItemAttributesId)
  48.                 {
  49.                     DataRow dr = resultado.NewRow();
  50.                     dr["IssueId"] = row.ItemAttributesId;
  51.                     dr["IssueType"] = row.issuetype;
  52.                     dr["Database Name"] = row.Value;
  53.                     dr["Issue"] = row.issue;
  54.                     dr["IssueText"] = row.issuetext;
  55.                                                  …
  56.                  }
  57.              }
  58.              …
  59.             return(resultado);
  60. }

Con esa sencilla consulta (a la que por supuesto podemos añadir todas las columnas que queramos), podemos obtener un DataTable que facilmente podemos exportar al formato que queramos (separado por comas o directamente a Excel usando la API OpenXML o Excel Interop).

Ahora tenemos la información procesada por nosotros, y en tan solo 5-10 minutos podremos tener nuestro exportador de datos de SSUA, al que por ejemplo le añadamos información extra relativa a tiempos estimados de análisis o migración basándonos en nuestra experiencia (como por ejemplo ocurre en nuestro HealthCheck).

martes, 2 de noviembre de 2010

SolidQ Journal Octubre 2010 en castellano liberado!

Ha sido liberada la versión en castellano del SolidQ Journal en su edición de Octubre 2010.

image Este mes en The SolidQ Journal​, vea lo que sucede cuando la compañía de investigación y análisis del mercado inmobiliario Hanley Wood confió en Solid Quality Mentors para la creación de un sistema analítico que ayude a los clientes a reducir costes, mitigar el riesgo e identificar nuevas oportunidades en la industria inmobiliaria. Nuestra edición de Octubre también incluye al MVP en SharePoint, Daniel Seara, tratando sobre las búsquedas FAST en SharePoint 2010; a Greg Low con vistas, procedimientos almacenados, y abstracción; Herbert Albert y Gianluca Hotz con la continuación de su artículo sobre restauración con PowerShell; y a Enrique Catalá hablando sobre la detección de patrones de consulta ineficientes en un entorno real. A continuación, tenga un uno a uno con el miembro de SolidQ, Antonio Soto, en su misión de erradicar los datos erróneos.

 

Como sabes, la revista es completamente gratuita y está disponible a traves de la web siguiente http://www.solidq.com/sqj/es/Pages/Home.aspx

En este caso, para ir diréctamente a la versión Octubre 2010 en castellano puedes acceder a traves de: http://www.solidq.com/sqj/es/Pages/Home.aspx?dates=October,%202010&enddatetime=2010-10-31T00:00:00&startdatetime=2010-10-29T00:00:00

Ya sabes que la tienes disponible tambien en Ingles y Portugues!

lunes, 1 de noviembre de 2010

¿Por qué debemos evitar funciones escalares T-SQL?

Hoy me he decidido a escribir sobre por qué las funciones escalares T-SQL no son buena opción. Esto es otra vez mas, algo que veo como un patrón recurrente en todos los clientes que visito y siempre acabo recomendando que sean eliminados, aunque lamentáblemente muchas veces solo se hace en los escenarios críticos…es decir, la/las consultas o patrones T-SQL maléficos que les detecto que están destrozando a su pobrecito SQL Server Smile

Antes de nada me gustaria recordar las razones por las que evitar siempre utilizar una funcion escalar en SQL Server:

  1. No son visibles en los planes de ejecución
  2. Producen malísimas estimaciones estadísticas que derivan en el uso inadecuado de operadores NESTED LOOPS
  3. El código de la función se interpreta en cada llamada (cada fila)
  4. Por último y lo más importante de todo: NO ES POSIBLE EL PARALELISMO

Independientemente de cual sea la razón por las que uno piense en utilizarlas, hay que quitarse la idea de la cabeza. Y no, no me vale eso de “pero esque así la consulta T-SQL queda más limpia y bonita” o “esque así reutilizo código”. 

Para rebatir cualquier afirmación pienso que un ejemplo vale más que 1000 palabras:

use tempdb
go

if (object_id('dbo.TablaGrande') is not null)
drop table dbo.TablaGrande
go

-- Creamos una tablita con 100k filas para el ejemplo
--
with
t0 as (select n = 1 union all select n = 1),
t1 as (select n = 1 from t0 as a, t0 as b),
t2 as (select n = 1 from t1 as a, t1 as b),
t3 as (select n = 1 from t2 as a, t2 as b),
t4 as (select n = 1 from t3 as a, t3 as b),
t5 as (select n = 1 from t4 as a, t4 as b),
result as (select row_number() over (order by n) as n from t5)
select n col1 ,n+1 col2
into dbo.TablaGrande
from result where n <= 1000000

-- Le creo 2 índices, por hacer algo, realmente tampoco es
-- imprescindible
create clustered index ci_tablagrande on TablaGrande(col1 asc)
create nonclustered index nci2_tablaGrande on TablaGrande(col2 asc)

-- Creamos una función tonta para ilustrar que incluso la cosa
-- mas increiblemente tonta produce resultados desastrosos
--
if (object_id('dbo.ChorraFuncion') is not null)
drop function dbo.ChorraFuncion
go
create function dbo.ChorraFuncion( @a int,@b int)
returns varchar(100)
begin
return cast((@a+@b) as varchar(100))
end

-- ponemos en marcha la salida de tiempos
--
set statistics time on

-- Para no hacer trampas, borramos cualquier página útil
-- para que sean ejecuciones vírgenes
dbcc dropcleanbuffers
go

-- Usando la función, aqui vemos los tiempos en mi máquina:
--
-- SQL Server Execution Times:
-- CPU time = 5444 ms, elapsed time = 6229 ms.
--
select max(dbo.ChorraFuncion(t1.col1,t2.col2))
from TablaGrande t1
inner join TablaGrande t2 on t1.col1 = t2.col2
go

dbcc dropcleanbuffers
 
-- Expandiendo la función (sin llamarla, pero haciendo lo mismo que hace), vemos como los tiempos son radicalmente mejores
-- SQL Server Execution Times:
-- CPU time = 3711 ms, elapsed time = 1118 ms.
--
select max(cast((t1.col1 + t2.col2) as varchar(1000)))
from TablaGrande t1
inner join TablaGrande t2 on t1.col1 = t2.col2
go



La razón de esto ya la he comentado anteriormente, pero quizás se aprecie mejor viendo por un lado el plan de ejecución:


En serie cuando lanzamos la consulta con la llamada a ChorraFunción:


image


Y en paralelo cuando no la usamos:


image



Por cierto…¿Ves por algún lado en el plan de ejecución en serie referencia alguna a la función? (si, es eso que pone “Compute Scalar” y que afirma erroneamente que tiene coste 0%.


Además, si dejamos puesto el SQL Server profiler, en la ejecución de la query que usa ChorraFuncion podemos ver si capturamos el evento SP:SmptCompleted, las ejecuciones de la función que hay por cada una de las filas procesadas (en este caso han sido 1 millon de ejecuiones)


image

domingo, 31 de octubre de 2010

Solución al error “allow remote connections through DCOM”

Cuando tratamos de conectar remotamente a SSIS eventualmente podemos recibir el siguiente mensaje de error, cuando no hemos realizado una correcta configuración de seguridad:

image

En este caso lo que se nos está diciendo es que aunque hemos llegado al servicio, se nos ha denegado el acceso. Además de esto nos está dando una pista que es debido a que no hemos configurado correctamente el acceso remoto.

La solución es bien sencilla y pasa por añadir en la configuración DCOM del servicio MsDtsServer100 o MsDtsServer (según si estamos en SQL Server 2008 o 2005) al usuario que queremos que tenga acceso remoto y listo.

Para ello abrimos “Component services”, buscamos dentro de DCOM las propiedades del servicio MsDtsServer100 y añadimos en su pestaña de seguridad al usuario en cuestión:

image

Buscamos en DCOM la configuración de MsDtsServer o MsDtsServer100 (según si es Sql Server 2005 o 2008)image

En las propiedades, se añaden los permisos que necesitemos para el usuario que queramos que conecte remoto:image

Para más información, recomiendo leer el siguiente artículo: http://msdn.microsoft.com/en-us/library/aa337083.aspx

miércoles, 27 de octubre de 2010

Liberada la nueva edición SolidQ Journal Octubre

Ha sido liberada la nueva edición SolidQJ de octubre

This month in The SolidQ Journal, see what happens when real estate research powerhouse Hanley Wood turns to Solid Quality Mentors for an advanced analytical system that helps clients cut costs, mitigate risk, and identify new opportunities in the housing industry. Our October issue also features SharePoint MVP Daniel Seara on FAST search for SharePoint 2010; Greg Low on views, stored procedures, and abstraction; Herbert Albert and Gianluca Hotz’s next iteration of their PowerShell restore solution; and Enrique Catalá on detecting inefficient query patterns through query aggregation. Then go one-on-one with SolidQ’s Antonio Soto on his mission to stamp out bad data.​

Si deseas leer más recuerda que es gratuita y la tienes aqui: http://www.solidq.com/sqj/Pages/Home.aspx