Resulta que la implementación de los operadores en SQL Server 2014 y 2012 respecto a los índices columnares no era completa y que el generador de planes de ejecución no tenia algunas optimizaciones aplicadas al respecto además. Vamos, que en SQL Server 2014, tus tablas que tienes perfectamente indexadas con índice columnar, van a medio gas, a pesar de lo rápido que creas que van tus queries.
miércoles, 2 de agosto de 2017
jueves, 13 de julio de 2017
Data Migration Asisstant Helper
He publicado en GitHub el repositorio que contiene un helper para analizar el resultado de la herramienta Data Migration Asisstant. He recopilado y mejorado la versión que liberó Microsoft el pasado Marzo para procesar resultados agregados de múltiples servidores con la herramienta de analisis de código estático de Microsoft.
Lo puedes encontrar aqui: https://github.com/enriquecatala/DataMigrationAssistantHelper y en la versión actual es compatible con la version 3.1 (la última en el momento de escribir este artículo)
lunes, 12 de septiembre de 2016
Evento: Planifica la migración de tus BBDD a SQL Server 2016
En este seminario te mostraré cómo planificamos en SolidQ la migración a SQL Server 2016 para que te pongas manos a la obra. Además conocerás las diferentes fases de un proyecto de mirgación: Análisis previo e incompatibilidades, eliminación de posibles incompatibilidades, pruebas de migración y la migración…
| Cuándo? | Lugar |
| 29 de Septiembre de 10:00 a 13:30 | Oficinas Microsoft Ibérica |
Beneficios de asistir al evento
- Ponte al día. Conoce las últimas novedades tecnológicas en una mañana y la opinión de otros expertos sobre ellas
- Soluciona tus problemas. Compártelos con nuestros mentores y llévate ideas y soluciones para ellos
- Detectarás problemas y soluciones que aún no se te han planteado o no has identificado como tales
Solo hay 13 plazas abiertas por lo que si no quieres quedarte sin ella…regístrate aqui.
lunes, 14 de noviembre de 2011
Ebook gratuito: Planificando migracion a SQL Server 2008 R2
"El proceso de migración a SQL Server 2008 R2 no deberia ser un proceso traumático. Para conseguirlo, hay que consensuar un plan lo suficientemente robusto y estable como para satisfacer todas las posibles particularidades del entorno que desee migrar. Hay que ser consciente que como en cualquier proceso de riesgo, si es llevado a cabo negligentemente puede producir un resultado final lleno de errores e incompatibilidades de última hora que produzcan una migración traumática, defectuosa, o incluso que se deba abortar.
..."
Para seguir leyendo, registrate y descarga gratis el ebook: http://www.solidq.com/sqj/books/Pages/Planificando-la-migracion-a-SQL-Server-2008-R2.aspx
Autor: Enrique Catalá Bañuls
Revisores: Eladio Rincón
Páginas: 102
Idioma: Español
Publicado: Noviembre, 2011
Precio: Gratuito
ISBN: 978-84-936417-9-5
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.
No obstante, SSUA nos ofrece la posibilidad de exportar la información a un fichero .csv
Cuyo resultado es como el siguiente (después de procesarlo introduciendo sus valores en celdas):
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
Una vez pulsado ahí, obtendremos su esquema .xsd
Como vemos, nada nuevo. La gracia viene ahora.
Podemos crearnos un proyecto de Visual Studio, al que añadir el siguiente código:
- public static DataTable Analyze(string pathToXml)
- {
- FillIssueTimming();
- DataSet ds = new DataSet();
- ds.ReadXmlSchema("SSUA\\XMLSchemas\\DE.xsd");
- ds.EnforceConstraints = false;
- XmlDataDocument xml = new XmlDataDocument(ds);
- xml.Load(pathToXml);
- var query = from ia in ds.Tables["ItemAttribute"].AsEnumerable()
- join ias in ds.Tables["ItemAttributes"].AsEnumerable()
- on ia.Field<int>("ItemAttributes_id") equals ias.Field<int>("ItemAttributes_id")
- join item in ds.Tables["Item"].AsEnumerable()
- on ias.Field<int>("Item_id") equals item.Field<int>("Item_id")
- join r in ds.Tables["Report"].AsEnumerable()
- on item.Field<Nullable<byte>>("ItemId") equals r.Field<Nullable<byte>>("ItemId")
- join iss in ds.Tables["Issue"].AsEnumerable()
- on r.Field<Nullable<byte>>("IssueId") equals iss.Field<Nullable<byte>>("IssueId")
- select new
- {
- ItemAttributesId = ia.Field<int>("ItemAttributes_id"),
- Name = ia.Field<string>("Name"),
- Value = ia.Field<string>("Value"),
- Issue = iss.Field<string>("IssueDescription"),
- IssueText = iss.Field<string>("IssueText"),
- IssueType = iss.Field<string>("IssueType")
- };
- // Get all the info you want in the export file
- //
- DataTable resultado = new DataTable("results");
- resultado.Columns.Add("IssueId", typeof(int));
- resultado.Columns.Add("IssueType", typeof(string));
- resultado.Columns.Add("Source Type", typeof(string));
- resultado.Columns.Add("Database Name", typeof(String));
- resultado.Columns.Add("Object Name", typeof(String));
- resultado.Columns.Add("Object Type", typeof(String));
- resultado.Columns.Add("Keyword", typeof(String));
- resultado.Columns.Add("Issue", typeof(String));
- resultado.Columns.Add("SQL Batch", typeof(string));
- resultado.Columns.Add("Trace File", typeof(string));
- resultado.Columns.Add("IssueText", typeof(String));
- resultado.Columns.Add("Estimated time of adaptation", typeof(String));
- resultado.Columns.Add("Comments", typeof(String));
- foreach(var row in query)
- {
- if (issueid_old != row.ItemAttributesId)
- {
- DataRow dr = resultado.NewRow();
- dr["IssueId"] = row.ItemAttributesId;
- dr["IssueType"] = row.issuetype;
- dr["Database Name"] = row.Value;
- dr["Issue"] = row.issue;
- dr["IssueText"] = row.issuetext;
- …
- }
- }
- …
- return(resultado);
- }
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, 3 de agosto de 2010
Detectar consultas con referencias a bases de datos distintas a la actual
Un problema habitual en todo proyecto de migración, escalabilidad o rearquitectura de aplicaciones y/o servidores de bases de datos es la necesidad de conocer la interdependencia de bases de datos.
Los que me conocen, saben que yo apuesto siempre por molestar al cliente al mínimo y eso implica que aunque suelo pedir información relativa a la arquitectura actual, dependencias, etc, etc,…siempre acabo verificando por mi cuenta la realidad (parafraseando a house: “El paciente siempre miente, aunque no lo sepa” )
Bien, si tenemos que pelearnos con un problema como el que comento (que por ejemplo hayan aplicaciones conectadas a la BBDD X, que lancen queries del estilo “Select * from Y.dbo.tabla_en_bbdd_y”), hay una solución bien sencilla, pero que obviamente tarda su tiempecito
Consiste en usar trazas de profiler para capturar la actividad contra la BBDD. Una vez tenemos esta actividad, nos crearemos una BBDD o tabla en la que incorporaremos información relativa a database_id, databaseName y servername (se sobreentiende que esto se hace porque además del ejemplo que estoy exponiendo, hay que hacer algo parecido para referencias entre instancias, pero se sale del ámbito del post).
Una vez tenemos dicha tabla creada y rellenada (a la que llamaremos dbo.Databases), lo siguiente que tenemos que hacer por tanto es, a grandes rasgos:
- Obtener los SMTP: BatchCompleted events
- Obtener el databaseid de los mismos, junto a su TextData NOT NULL e información relevante como hostname, loginname,…y lo que queramos para posteriormente buscar datos en ellos
- Filtrar conexiones a bases de datos tipo pubs, adventureworks y northwind
- Por último, obtener aquel texto, en el que se haga referencia a cualquier databasename seguido por “.” y que además no sea el mismo databasename al que estaba la conexión atacando (referencia externa por tanto)
Obviamente pueden haber falsos positivos (igual, tenemos mala suerte y nos sale algun comentario donde se haga referencia,…), pero habrá positivos de haberlos.
No olvideis crear los índices adecuados en la tabla dbo.Databases para que la cosa no vaya lentísima.
Aqui os dejo el código para explorar los resultados:
--
-- ECB: Meta query to detect queries that references databases
--
--
declare @ServerName sysname = 'servidor_sql'
declare @trcFile nvarchar(max) = 'path_to_trc_file.trc'
;with subselect as(
select
dbs.dbid,
dbs.DBName,
textdata,
applicationName,
hostname,
loginname,
starttime
from ::fn_trace_gettable(@trcFile,default) trc
left join dbo.DataBases dbs on trc.DatabaseID = dbs.DBId
and dbs.ServerName = @ServerName
and dbs.dbid > 4 AND dbs.ServerName not in ('pubs','Northwind','Adventureworks')
where trc.textdata IS NOT NULL AND trc.EventClass = 12
)
select
trc.dbname as db_connected ,
dbs.dbName as db_referenced,
trc.applicationname,
trc.hostname,
trc.loginname,
trc.starttime,
cast(trc.textdata as nvarchar(1000)) as [definition]
from subselect trc, dbo.DataBases dbs
where dbs.servername = @ServerName
and dbs.DBId <> trc.DBId
and (trc.TextData LIKE '%'+dbs.dbname+'.%'
or textdata LIKE '%'+dbs.dbname+'].%'
)
Aqui veis el plan de ejecución, que siempre me gusta ver
Por último solo me queda comentar que esto mismo hay que hacerlo con los objetos de BBDD (procedimientos almacenados,funciones,…) y con servidores vinculados y aperturas tipo openrowset y similares.
Salu2!
martes, 27 de julio de 2010
Restaurar multiples bases de datos a la vez
En ocasiones hace falta realizar restauraciones masivas de ficheros de backup. Situaciones como resolver una catástrofe o realizar pruebas de migración, pueden requerirnos restaurar 40, 100 bases de datos…y aqui es donde entra este script.
Para el proyecto en el que estoy ahora involucrado, estoy realizando pruebas que involucran directamente restauraciones de más de 50 BBDD y claro…los informáticos no nos caracterizamos por nuesta pasión a las tareas repetitivas, asique…¿mejor que lo haga otro, no?. Pues bien, ese otro será nuestro SQL Server
Los parámetros de inicio del siguiente script son:
- dbs: Cursor con los nombres de ficheros de backup a restaurar (si se llama mibbdd.bak, pues mibbdd)
- pathFisicoMDF: Ruta donde acabarán los ficheros de datos
- pathFIsicoLDF: Ruta donde acabarán los ficheros de log
- pathToBak: Ruta donde buscar los ficheros de backup .bak
Solo una cosa mas,
/*
Enrique Catala Bañuls
*/
declare @path nvarchar(max)
DECLARE @dbName sysname
DECLARE @logicalName sysname
declare @physicalName nvarchar(max)
declare @fileName nvarchar(max)
declare @sSql nvarchar(max)
declare @fileType char(1)
declare @pathToBak nvarchar(max)
declare @pathFisicoMDF nvarchar(max)
declare @pathFisicoLDF nvarchar(max)
/*********************************************************************************************/
/*********************************************************************************************/
--
-- FILL HERE DATA NEEDED TO THE RESTORNG PROCESS
--
DECLARE dbs CURSOR READ_ONLY
-- bases de datos restaurándose
FOR select 'bdeap'
select @pathFisicoMDF = N'e:\datos\',
@pathFisicoLDF = N'd:\logs\',
@pathToBak = 'E:\fulldiaria\'
/*********************************************************************************************/
/*********************************************************************************************/
create table #tmp
(
LogicalName sysname
,PhysicalName nvarchar(max)
,Type char(1)
,FileGroupName sysname NULL
,Size numeric(20,0)
,MaxSize numeric(20,0),
Fileid tinyint,
CreateLSN numeric(25,0),
DropLSN numeric(25, 0),
UniqueID uniqueidentifier,
ReadOnlyLSN numeric(25,0) NULL,
ReadWriteLSN numeric(25,0) NULL,
BackupSizeInBytes bigint,
SourceBlocSize int,
FileGroupId int,
LogGroupGUID uniqueidentifier NULL,
DifferentialBaseLSN numeric(25,0) NULL,
DifferentialBaseGUID uniqueidentifier,
IsReadOnly bit,
IsPresent bit,
TDEthumbprint varbinary(32) NULL
)
OPEN dbs
FETCH NEXT FROM dbs INTO @dbName
WHILE (@@fetch_status <> -1)
BEGIN
IF (@@fetch_status <> -2)
BEGIN
SELECT @sSql = '',
@path = 'restore filelistonly from disk = N'''+@pathToBak+@dbName+'.bak'''
--PRINT @path
insert #tmp
EXEC (@path)
--select * from #tmp
DECLARE dbs2 CURSOR READ_ONLY
FOR select logicalName,physicalName,type from #tmp
OPEN dbs2
FETCH NEXT FROM dbs2 INTO @logicalName,@physicalName,@fileType
WHILE (@@fetch_status <> -1)
BEGIN
IF (@@fetch_status <> -2)
BEGIN
set @fileName= substring(@physicalName,
2+len(@physicalName)-charindex('\',reverse(@physicalName)),
charindex('\',reverse(@physicalName)))
if @fileType = 'D'
set @sSql = @sSql+' MOVE N'''+@logicalName+''' TO N'''+@pathFisicoMDF+@fileName+''','
else
set @sSql = @sSql + ' MOVE N'''+@logicalName+''' TO N'''+@pathFisicoLDF+@fileName+''','
--print @logicalName
--print @pathFisicoMDF
--print @sSql
END
FETCH NEXT FROM dbs2 INTO @logicalName,@physicalName,@fileType
END
CLOSE dbs2
DEALLOCATE dbs2
--print @dbName
--print @pathToBak
--print @sSql
--SET @sSql = 'RESTORE DATABASE ['+@dbName+'] FROM DISK = N'''+ @pathToBak +'\' +@dbName + '.bak''
SET @sSql = 'RESTORE DATABASE ['+@dbName+'] FROM DISK = N'''+ @pathToBak +'\' +@dbName + '.bak''
WITH FILE = 1, '
+@sSql+
' RECOVERY, NOUNLOAD, REPLACE, STATS = 10'
--print @sSql
exec(@sSql)
truncate table #tmp
END
FETCH NEXT FROM dbs INTO @dbName
END
CLOSE dbs
DEALLOCATE dbs
GO
drop table #tmp
jueves, 8 de julio de 2010
Transformar los resultados de SSUA en tupla
Si alguna vez has usado SQL Server Upgrade Advisor para analizar el estado actual de un servidor de SQL Server de cara a una migración, habrás podido notar que la herramienta en sí, aunque funciona como debe, peca en algunos aspectos…con solo tener que analizar más de 1 instancia ya te das cuenta de lo que te digo
Bueno, pues si a alguien (como es mi caso) no le apetece tener que lidiar con los ficheros DE.xml de resultado exportados a .csv que genera la herramienta por defecto…que sepa que se puede muy facilmente hacer uno un “parser” de dicho XML para hacer con la información lo que mejor se quiera.
Para esto lo único que tenemos que hacer es generarnos el .xsd de resultado (Visual Studio lo hace automático por nosotros), leer el XML a un DataSet y luego lanzar esta “sencilla” query LINQ2DataSet
var q = from ia in ds.Tables["ItemAttribute"].AsEnumerable()
join ias in ds.Tables["ItemAttributes"].AsEnumerable()
on ia.Field<int>("ItemAttributes_id")
equals ias.Field<int>("ItemAttributes_id")
join item in ds.Tables["Item"].AsEnumerable()
on ias.Field<int>("Item_id")
equals item.Field<int>("Item_id")
join r in ds.Tables["Report"].AsEnumerable()
on item.Field<Nullable<byte>>("ItemId")
equals r.Field<Nullable<byte>>("ItemId")
join iss in ds.Tables["Issue"].AsEnumerable()
on r.Field<Nullable<byte>>("IssueId")
equals iss.Field<Nullable<byte>>("IssueId")
select new
{
ItemAttributesId = ia.Field<int>("ItemAttributes_id"),
Name = ia.Field<string>("Name"),
Value = ia.Field<string>("Value"),
Issue = iss.Field<string>("IssueDescription"),
IssueText = iss.Field<string>("IssueText"),
IssueType = iss.Field<string>("IssueType")
};
Ahora solo te queda usar el objeto “q” para añadirle o toquetearle lo que quieras…una pista?…¿Qué tal que tu parser sea capaz de darte estimaciones temporales basado en el tipo de “Issue”?
Salu2!
martes, 6 de julio de 2010
Averiguar conexiones externas hacia nuestro SQL Server
Últimamente estoy participando en bastantes proyectos de migración de SQL Server 2000 a SQL Server 2008 R2. Independientemente de la arquitectura existente en cada cliente, siempre hemos de conocer la topologia de consultas que se lanzan y sobre todo QUIEN las lanza.
En un proyecto de migración nunca podemos dejar cabos sueltos y menos cuando uno de los cabos sueltos puede llevar a que aplicaciones (sean o no críticas) no funcionen.
La opción más sensata siempre es crear una traza de profiler para SQL Server 2000, que nos capture durante un tiempo prudencialmente amplio y significativo, la actividad de nuestro servidor
¿Qué nos interesa conocer?
- La consulta que ha sido lanzada (posteriormente lo utilizaremos para que SSUA analice si hay patrones conflictivos)
- El hostname desde donde se lanza
- El login utilizado
- El nombre de la aplicación
- La BBDD sobre la que se está ejecutando la consulta
Dicho esto, nos podemos hacer una idea de los eventos e información que necesitamos capturar en SQL Server profiler…y ahora viene la parte divertida…la explotación de esos datos ![]()
-- Create table with data
--
CREATE TABLE [dbo].ExternalConnectionAnalysis(
[ServerName] [nvarchar](256) NOT NULL,
[databaseid] [int] NULL,
[applicationname] [nvarchar](256) NULL,
[hostname] [nvarchar](256) NULL,
[loginname] [nvarchar](256) NULL,
queries_executed bigint not null
) ON [PRIMARY]
GO
INSERT into dbo.ExternalConnectionAnalysis(ServerName, databaseid,applicationname, hostname, loginname,queries_executed)
SELECT 'atlante3' AS ServerName , databaseid, applicationname,hostname, loginname,COUNT(*)
FROM ::fn_trace_gettable('path_to_file.trc', default)
GROUP BY databaseid, applicationname, hostname, loginname
go
Tenemos esa opción que evidentemente te lee el fichero de traza .trc (y los que vengan detrás en caso de haberse creado con multiples ficheros) y agrupa por la información que queremos, o podemos optar por una forma algo más rebuscada y eficiente para procesar los datos como esta otra:
declare @srvname sysname = 'my_server'
declare @trcpath varchar(max) = 'path_to_file.trc'
;
with existent_data as(
select ServerName, databaseid,
applicationname,hostname,loginname
from dbo.ExternalConnectionAnalisys
where ServerName = @srvname
),
trc as (
SELECT @srvname AS ServerName
, trc.databaseid, trc.applicationname,
trc.hostname, trc.loginname
FROM ::fn_trace_gettable(@trcpath, default) trc
)
INSERT into dbo.ExternalConnectionAnalysis(ServerName, databaseid,
applicationname, hostname, loginname,queries_executed)
SELECT @srvname AS ServerName , trc.databaseid, trc.applicationname,
trc.hostname, trc.loginname ,COUNT(*)
FROM trc left join existent_data ed on
(trc.DatabaseID = ed.databaseid
and trc.ApplicationName = ed.applicationname
and trc.HostName = ed.hostname
and trc.LoginName = ed.loginname
)
where ed.databaseid is null or ed.applicationname is null or
ed.hostname is null or ed.loginname is null
GROUP BY trc.databaseid, trc.applicationname, trc.hostname, trc.loginname
La gran ventaja de utilizar la consulta anterior radica principalmente en que es una consulta que solo añadirá las nuevas filas con información que le vayamos proponiendo. Es decir, que como es normal, tendremos ficheros de traza a traves del tiempo (cada dia previsiblemente tendremos .trc nuevos) y los podremos procesar independiemente de tener todos los ficheros de traza y procesarlos de golpe.
Evidentemente es una gran ventaja…pero otra ventaja oculta es si miras un poco más alla de la simple consulta y te das cuenta de que al utilizar el left join y el group by, nuestro SQL Server ha generado un plan de ejecución eficiente mediante un fantástico MERGE JOIN
Queda a tu disposición probar la consulta sin el left join, mediante un cruce de los de toda la vida y ver que ocurre…y sobre todo el tiempo que tarda, por culpa del super LOOP JOIN que te mete ![]()
Salu2!
martes, 26 de enero de 2010
Nuevo ebook sobre migración de SQL Server 2000 a SQL Server 2008
domingo, 5 de abril de 2009
¿Por qué migrar a SQL Server 2008?
Una pregunta que últimamente se da con frecuencia es la de: “vale, pero yo tengo mi sistema con SQL 2000 y me va bien ¿que gano yo instalándome el SQL 2008 si no voy a utilizar ninguna de sus novedades a priori?”. Para este tipo de cuestiones, evidentemente uno se puede poner a enumerar una por una todas y cada una de las novedades que aparecen en SQL Server 2008, pero eso no le resolverá la duda a la persona que la plantea, sino que probablemente piense que tiene un montón de “extras” que no le sirven para nada (datos espaciales, jerárquicos,…).
Es por ello, que en este post voy a poner algunas de las razones que a mi modo de ver, son las mejoras mas significativas que se nos ofrecen, por el simple y mero hecho de instalar SQL Server 2008 y restaurar ahí nuestra BBDD de SQL 2000:
- Compresión de datos
Como sabemos, en SQL Server 2008 disponemos de la posibilidad de realizar compresión de datos. En algunos posts anteriores (este y este) , ya discutí las bondades de disponer de esta característica. Ciertamente, el disponer de entrada, de la posibilidad de comprimir datos o backups, es algo muy a tener en cuenta. Es más, todavía me falta el post III de III, donde se podrán ver las grandes mejoras en cuanto a rendimiento se refiere, de activar la compresión de datos.
- Resource Governor
Gracias a Resource Governor, vamos a poder conseguir que el motor relacional se comporte como queremos. Se acabaron las consultas que nos tumban el servidor, aquellos reports que lanzaba el director cuando le apetecía una y otra vez que nos ralentizaban a todos, esas consultas críticas que no salían cuando se las necesitaba porque el becario estaba jugueteando con eso llamado T-SQL en producción,…
- Consolidación de servidores
Gracias a la característica de “administración centralizada de servidores” (Central Management Servers), podremos gestionar múltiples servidores de forma simultanea. Desde el mismo momento en que instalemos SQL Server 2008, podremos gestionar SQL 2008, SQL 2005 e incluso SQL 2000 de una manera centralizada, validando políticas de seguridad, lanzando comandos T-SQL de administración,…Es decir, que por el mero hecho de tener un único SQL 2008, nos vamos a beneficiar incluso en la gestión de servidores de otras ediciones.
- Transparent Data Encryption
¿Te has parado a pensar en qué ocurre si un backup de producción cae en malas manos? Quizás estás pensando que realmente no pasa nada porque tu ya estás implementando encriptación a nivel de columna mediante certificados en SQL Server 2005…; ¿y si te dijera que con solo lanzar un comando, SQL Server 2008 cifra TODO y además de forma transparente a tus aplicaciones? Pues es posible y se llama TDE (Encriptación transparente de datos), una característica por la que incluso los propios backups realizados sobre una BBDD cifrada mediante TDE son imposibles de restaurar sin su certificado y/o password, y están completamente cifrados.
- Consultas mas eficientes para tipos de datos fecha
Con la aparición de los nuevos tipos de datos fecha, aparece el tipo de datos “date”. Gracias a el, cuando deseemos realizar una consulta a un datetime o smalldatetime para obtener datos filtrados por una fecha en particular, podremos realizar una consulta mas natural y eficiente de la siguiente forma:
select * from dbo.TestIndexSeek where cast(sample_datetime as date) = '20071208';
*NOTA: sample_datetime puede ser de tipo datetime o smalldatetime, no es necesario que cambiemos nada en nuestro modelo EER
Este tipo de consultas, pese a lo que se pueda pensar al ver el cast al lado izquierdo de la comparación, ahora son eficientes (se entiende que existe un índice sobre sample_datetime).
- Múltiples hilos para consultas sobre datos particionados
En SQL Server 2005, si una consulta debía recorrer múltiples particiones para devolver los resultados, solo existía un único hilo para recorrerlas. En SQL Server 2008, mejoras en el motor relacional hacen que existan múltiples hilos no solo para recorrer cada partición, sino para aquellas operaciones que deben moverse entre particiones para devolver datos
- Indexación eficiente mediante filtrado de índices
Ahora es posible definir índices filtrados. Si conocemos que existen consultas que filtran datos sobre columnas cuya distribución de datos solo hace posible la utilización del índice en escasos predicados, podemos hacer un índice filtrado que optimice dichas consultas únicamente. Con ello obtendremos un índice mas ligero, puesto que solo será mantenido para el predicado que le hayamos dicho nosotros
CREATE NONCLUSTERED INDEX idx_territory5_orderdate
ON Sales.SalesOrderHeader(OrderDate)
INCLUDE(SalesOrderID, CustomerID, TotalDue)
WHERE TerritoryID = 5;
- Seguimiento de cambios y de datos y mejoras en auditoria
En SQL Server 2008 existen las características CDC (Change Data Capture) y CT (Change Tracking) mediante las cuales podemos realizar un seguimiento de cambios de nuestros datos. De forma muy simple, podemos activar las características mediante las cuales podemos saber no solo cuantas veces ha cambiado un dato de valor, sino incluso todos los cambios por los que ha pasado e incluso (esto ya con algo de trabajo por nuestra parte) quién lo ha realizado.
¿te gustaría saber si alguien trata de obtener información sobre tu nómina? Puedes activar otra característica llamada Auditing, por la cual puedes incluso saber quien está lanzando una select (con su query) que implique lectura de alguna tabla.
- TVP
Las siglas TVP (Table Value Parameters) hacen referencia ni mas ni menos que a la posibilidad de que nuestras aplicaciones puedan enviar tablas como parámetros de entrada de procedimientos almacenados y funciones। Algo que a priori quizás no le veas mucho sentido si no te paras a pensarlo, pero que supone un aumento de rendimiento brutal porque simplemente, SQL Server trabaja mejor con conjuntos, por lo que es exageradamente mas eficiente procesando una actualización de 100 filas, que 100 actualizaciones de una fila।
Este último realmente requiere que las aplicaciones cliente le saquen provecho, pero no he podido dejarlo pasar en este post porque me encanta ;)
Como se ha podido ver, existen numerosas características en SQL Server 2008 aprovechables de entrada, sin necesidad de tener que hacer un esfuerzo considerable ni mucho menos (algunas ya las obtenemos simplemente al restaurar el backup sobre 2008).
En cualquier caso, estas características no son ni mucho menos las únicas que aparecen en SQL 2008 y sino, aquí va una prueba:
domingo, 29 de marzo de 2009
Migración de SQL Server 2000 a 2008 y SQL Profiler
Cuando uno se plantea una migración de SQL Server, no solo se plantea analizar el propio servidor y las BBDDs, sino que debe plantearse también las aplicaciones cliente. Un argumento más para tener en cuenta en pro del uso de procedimientos almacenados es que el Sql Server Upgrade Advisor (SSUA a partir de ahora) es capaz de analizar los objetos de la BBDD y por lo tanto será capaz de detectar código “deprecated” en el mismo. Puesto que las aplicaciones cliente en ocasiones generan T-SQL ad-hoc, la aplicación SSUA nos provee de análisis de trazas de profiler capturadas. De este modo, podremos generar una traza de profiler sobre el servidor X y posteriormente pasársela al SSUA y que nos diga si realmente existen sentencias depreciadas que hayan sido originadas por nuestras aplicaciones.
Para ello, hagamos lo siguiente:
- Abrir SQL Server Profiler 2000 (nótese que pongo 2000, no 2008 – ver final del post-)
- Capturar una traza “Replay”. Puesto que capturar una traza replay genera una alta cantidad de información, lo primero que podemos hacer es crear una traza que contenga los eventos SQL:BatchStarting, SQL:SmtpStarting y RPC:Starting. Esta traza ocupará bastante menos que la de Replay y podremos realizar los análisis de forma previa mas rápidos.
- Dejar correr la traza para capturar las consultas que llegan desde aplicaciones cliente (en nuestro caso, únicamente he lanzado una select depreciada que veremos al final).
- Una vez capturada información durante un tiempo prudencial y representativo (1 semana?), la podemos salvar a fichero (eso en el caso de que no la hayamos scriptado, claro)
- Una vez tenemos la traza de profiler a buen recaudo, procederemos a analizarla con el SSUA 2008
- Nos conectamos a SQL Server 2000 (no hace falta que sea producción, podemos usar cualquier SQL Server 2000 que tengamos por ahí)
- Una vez indicado el servidor, indicaremos que deseamos analizar únicamente la traza de profiler (en la versión SSUA 2005, no era posible analizar únicamente profiler sin especificar BBDD)
- Una vez hecho esto, SSUA se pondrá a realizar el análisis de la traza de profiler. En este punto, la aplicación se conectará contra la instancia de SQL Server 2000 indicada y comenzará a realizar el análisis. para ello, ni mas ni menos se pone a ejecutar queries como un loco, para ver si alguna de las reglas de validación de queries depreciadas es violada (podemos activar el profiler si tenemos curiosidad y ver que tipo de información recupera).
- Para este ejemplo, puesto que solo me interesa analizar la traza, los mensajes relativos a la instancia de SQL Server no son relevantes, por eso los obvio y me centro en únicamente el que se encuentra señalado en rojo.
Como vemos, el mensaje me indica que en el fichero de trazas se encuentra un SQL Batch concreto (el que se puede apreciar en la imagen). Se nos proporciona información relativa a como solucionarlo y cual es su problema (no se ve en la imagen, pero está detrás), aunque lo importante aquí es que hemos sido capaces de detectar correctamente una sentencia generada de forma AD-HOC por alguna de nuestras aplicaciones (ya nos preocuparemos nosotros de detectar quien ha originado la petición, viendo la traza de profiler).
IMPORTANTE: La traza de profiler ha de ser generada con la versión de SQL Profiler del motor SQL Server que deseemos migrar (SQL 2000 o 2005), puesto que optimizaciones en la estructura del fichero de trazas entre versiones de SQL Server hacen imposible su lectura en compatibilidad hacia atrás. Quiero decir, que si por error creáis la traza de profiler, desde SQL Profiler 2008, SSUA no va a ser capaz de analizarla y por algun tipo de bug no nos avisará de ello.