martes, 4 de diciembre de 2012

Arranque Dual desde VHD usando Windows

Antecedentes

Por diversas necesidades de desarrollo y formación, en mi portátil siempre he necesitado de dos entornos: Un Sistema Operativo con aplicaciones de usuario (leáse Windows 7 o ahora Windows 8), y un Sistema Operativo de servidor (Windows Server 2008R2 o el recientemente aparecido Windows Server 2012). Por este motivo, ya hace un tiempo implementé una solución de Arranque Dual mediante discos duros virtuales (Virtual Hard Disks o VHD). A diferencia de muchas otras soluciones que encontraréis en la web, partiremos de un entorno sin ningún sistema operativo instalado, ya que lo que queremos es que todos ellos estén basados en el uso de discos duros virtuales.

Recursos

Gracias al artículo "Dual Boot from VHD using Windows 7 and Windows Server 2008R2", publicado en la web de Technet, pude implementarlo de forma rápida y sencilla (aunque no llevéis muy bien el inglés, creo que los scripts se pueden entender bastante bien). Básicamente lo que se pretende es definir un disco duro virtual con un tamaño concreto (en el ejemplo, 20GB expandibles), a partir del cuál se puede instalar el sistema operativo. Aunque en el ejemplo se habla de Windows 7 y Windows Server 2008R2, el ejemplo es aplicable a cualquier sistema operativo.
De hecho, si no os sentís cómodos con los scripts, podeís hacer una instalación de cualquier sistema operativo con los pasos descritos, y posteriormente usar desde éste, el asistente visual de creación de discos duros virtuales.
En el artículo "How to Create Windows 8 VHD for Boot to VHD using simple, easy to follow steps" de Technet tenéis el ejemplo de creación de un disco duro virtual con Windows 8 desde una máquina que ya tiene instalado Windows 7. Después de tener instalado el arranque dual en Windows 8, os debería aparecer una imágen como la siguiente:


¡Importante! En muchos de los artículos y ejemplos que encontraréis en la web, se pide el uso de la herramienta ImageX, que forma parte del WAIK (Windows Installation Kit), y que ocupa nada más y nada menos que 1,2GB. Para ahorraros este paso, podéis pedir directamente la herramienta a Microsoft rellenando los datos que aparecen en este formulario: KB2525084 Hotfix de la web de soporte (sólo tenéis que indicar una dirección de correo a la que os enviarán el fichero ImageX.exe de forma automática).

Otros comentarios

Actualmente ya podéis encontrar infinidad de artículos donde se explican este tema. Únicamente he querido recopilar algo de información de utilidad.Os adjunto otros artículos de interés:
¡Enjoy Windows 8!

jueves, 19 de abril de 2012

Radiografía del Freelance

Desde hace 6 años y medio que trabajo como profesional independiente, también conocido como freelance. Como todo trabajo tiene sus ventajas e inconvenientes, pero no quería dejar pasar la oportunidad de mostraros ésta infografía, que responde a algunas preguntas básicas sobre esta forma de trabajo (¡y de vida!).




Observando con detenimiento el gráfico, se puede ver como la principal ventaja consiste en la flexibilidad en el trabajo, aunque por contra, no se gana tanto dinero como trabajando por cuenta ajena. Por mi experiencia profesional no podría estar más de acuerdo con esta afirmación.
¿Alguien con experiencia como freelance? ¿Alguna/o se está planteando esa posibilidad? 


¡Enjoy freelancing!

miércoles, 18 de abril de 2012

Grupos de Disponibilidad en SQL Server 2012 AlwaysOn

Con la aparición de SQL Server 2012 se han añadido nuevas funcionalidades inexistentes en versiones anteriores y que vienen a mejorar, y mucho, las capacidades y disponibilidad de nuestros servidores de bases de datos. Una de las nuevas funcionalidades es SQL Server Always On, gracias a la cuál se potencia la alta disponibilidad del sistema. 
Con Always On podemos hacer un reflejo de base de datos (database mirroring) de un conjunto de bases de datos (Grupos de Disponibilidad, o Availability Groups) en otro servidor, y en el caso de caída del primero, levantar el segundo (manualmente o automáticamente) con todas esas bases de datos. Si queréis practicar y probar esta nueva funcionalidad de forma totalmente gratuita, os recomiendo encarecidamente este laboratorio.
Aun así he querido recopilar algunas FAQs que han aparecido respecto a los Grupos de Disponibilidad, y que se encuentran en este post en inglés.

  • P: ¿Para implantar un Grupo de Disponibilidad, se necesita un clúster de conmutación por error de Windows?
  • R: Sí.
  • P: ¿Por qué se necesita un cluster de conmutación por error de Windows si el reflejo de una base de datos no lo necesitaba anteriormente?
  • R: El reflejo de la base de datos se apoyaba en el mecanismo de quorum definido en una instancia testigo (witness), mientras que ahora este mecanismo se apoya en el Sistema Operativo, dónde está mucho más probado
  • P: ¿Qué versión de Windows se necesita para implantar un clúster de conmutación por error?
  • R: Se requiere la versión Windows Enterprise.
  • P: ¿Qué versión de SQL Server 2012 se necesita para implantar los Grupos de Disponibilidad?
  • R: Se requiere la versión SQL Server 2012 Enterprise.
  • P: ¿Se necesita un Directorio Activo?
  • R: Sí. El clúster de conmutación por error requiere la creación de algunos objetos en el Directorio Activo y de acceso al servidor/es DNS. Además el servidor donde se encuentra alojado el Directorio Activo no puede pertenecer al clúster.
  • P: ¿Los nodos del clúster deben pertenecer al mismo dominio?
  • R: Sí. Esto puede suponer un handicap si se quiere actualizar a esta funcionalidad desde un trasvase de registros (log shipping) entre instancias de bases de datos ubicadas en servidores de dominios distintos.
  • P: ¿Se puede montar el clúster en un entorno virtual?
  • R: Sí, siempre y cuando el entorno esté supervisado con un hypervisor soportado.
  • P: ¿Qué es el Listener?
  • R: El Listener es un objeto que contiene una dirección IP o de red y que se asigna cuando se crea el clúster de conmutación por error. De esta manera, en lugar de conectarnos a los nodos, nos conectaremos al Listener, abstrayendo el lugar donde se encuentra la instancia de la base de datos. De esta manera, las aplicaciones y los usuarios solo tienen un único punto de entrada. Solo hay un Listener por cada Grupo de Disponibilidad, y éste no puede ser compartido entre distintos grupos. 
  • P: ¿Se pueden usar las réplicas o nodos secundarios para leer datos o realizar copias de seguridad?
  • R: Sí. En función de como se configuren los nodos secundarios, todas las réplicas de un Grupo de Disponibilidad se pueden usar como bases de datos de sólo lectura. Los datos estarán actualizados casi en tiempo real y además se podrán realizar copias de seguridad completas o del registro de transacciones (con la opción COPY_ONLY), aunque no la diferencial.
  • P: ¿Cómo es posible leer de las réplicas?
  • R: Mediante el uso de objetos temporales, almacenados en la BBDD de sistema TempDB. Para minimizar los bloqueos de las operaciones de escritura, se usan transacciones con niveles de bloqueo snapshot. Por este mismo motivo se recomienda usar un hardware adecuado (CPU, sistema de disco) para los nodos secundarios si se pretende leer en ellos.
  • P: ¿En un Grupo de Disponibilidad pueden existir distintas bases de datos?
  • R: Sí. Un Grupo de Disponibilidad estará formado por una o más BBDD. Aun así, estas BBDD deben estar en la misma instancia.
  • P: ¿Puede una BBDD participar en distintos Grupos de Disponibilidad?
  • R: No. Una BBDD sólo puede pertenecer a un Grupo de Disponibilidad.
  • P: ¿Las BBDD que pertenecen a un Grupo de Disponibilidad se tratan de forma independiente?
  • R: Sí. Aunque si se produce una conmutación por error se tratarán todas las BBDD como una única unidad, el proceso de réplica/reflejo se realizará de forma independiente por BBDD.
  • P: ¿Existen dependencias con trabajos de SQL Server o logins?
  • R: Sí. Un Grupo de Disponibilidad es un objeto que reside fuera de las propias BBDD, con lo que se debe tener en cuenta en nuestras planificaciones.
  • P: ¿Es AlwaysOn lo mismo que los Grupos de Disponibilidad?
  • R: No. AlwaysOn es la funcionalidad que cubre los clúster de conmutación por error y los Grupos de Disponibilidad.
  • P: ¿Qué sucederá con la funcionalidad de Reflejo de BBDD (database mirroring)?
  • R: En futuras versiones de SQL Server está funcionalidad quedará obsoleta, ya que queda cubierta con los Grupos de Disponibilidad. Igualmente, que no cunda el pánico, ya que deberán pasar dos versiones principales del producto hasta que quede totalmente obsoleta, con lo que habrá tiempo de sobra para planificar la actualización al nuevo sistema.
  • P: ¿Es HADRON lo mismo que los Grupos de Disponibilidad?
  • R: Sí. HADRON era el nombre original para los Grupos de Disponibilidad, y por eso se usa en algunas Funciones y Vistas de Administración Dinámica (Dynamic Management Views).
Aunque seguro que hay preguntas que aún quedan en el tintero, espero haberos ayudado a tener una visión más clara de lo que son los Grupos de Disponibilidad en AlwaysOn y para que os pueden servir.
¡Enjoy SQL2012!



viernes, 16 de diciembre de 2011

Optimización en SQL Server: Consultas fundamentales

Frecuentemente nos podemos encontrar con problemas de rendimiento de nuestro servidor de bases de datos. Detectar donde se encuentra el cuello de botella y cuáles son las causas que lo producen se convierte en una tarea fundamental para cualquier DBA. ¿El problema se encuentra en la parte más física (CPU, memória, disco) del servidor? O por el contrario, ¿se encuentra en el diseño más lógico (diseño de las bases de datos, consultas, índices, etc.)
Para detectar problemas a nivel de hardware podemos usar los contadores de rendimiento, que nos permitirán comprobar "la salud" de nuestro servidor y ver donde podemos tener el cuello de botella. Aun así, por muy potente que sea nuestro hardware, el servidor no responderá adecuadamente si el diseño de las bases de datos no es correcto o no está optimizado.
Centrándonos en este último punto, os quería presentar algunas consultas que nos pueden ser de utilidad para detectar qué consultas o procedimientos almacenados están "presionando" la CPU, el disco y la memoria:
Procedimientos almacenados más ejecutados frecuentemente
SELECT TOP 100 qt.text AS 'Nombre_SP',
qs.execution_count AS 'NumEjecuciones',
qs.execution_count/DATEDIFF(Second, qs.creation_time, GetDate()) AS 'Llamadas/Segundo',
(qs.total_worker_time/qs.execution_count)/1000000.0 AS 'PromedioTiempoEjecucion(s)',
qs.total_worker_time/1000000.0 AS 'TiempoTotal(s)',
qs.max_logical_reads AS 'LecturasLogicas', 
qs.max_logical_writes AS 'EscriturasLogicas', 
qs.total_physical_reads AS 'LecturasFisicas',
DATEDIFF(Minute, qs.creation_time, GetDate()) AS 'TiempoCache(min)'
FROM sys.dm_exec_query_stats AS qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) AS qt
WHERE qt.dbid = db_id()
ORDER BY qs.execution_count DESC
Procedimientos almacenados más costosos para la CPU
SELECT TOP 20 qt.text AS 'Nombre_SP', 
qs.total_worker_time/1000000.0 AS 'TiempoTotal(s)',
(qs.total_worker_time/qs.execution_count)/1000000.0 AS 'PromedioTiempoEjecucion(s)',
qs.execution_count AS 'NumEjecuciones',
qs.execution_count/DATEDIFF(Second, qs.creation_time, GetDate()) AS 'Llamadas/Segundo',
qs.max_logical_reads AS 'LecturasLogicas', 
qs.max_logical_writes AS 'EscriturasLogicas', 
qs.total_physical_reads AS 'LecturasFisicas',
DATEDIFF(Minute, qs.creation_time, GetDate()) AS 'TiempoCache(min)'
FROM sys.dm_exec_query_stats AS qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) AS qt
WHERE qt.dbid = db_id()
ORDER BY qs.total_worker_time DESC
Procedimientos almacenados más costosos para la memoria
SELECT TOP 20 qt.text AS 'Nombre_SP',
total_logical_reads AS 'TotalLecturasLogicas',
qs.execution_count AS 'NumEjecuciones',
(total_logical_reads/qs.execution_count)/1000000.0 AS 'PromedioLecturasLogicas',
qs.execution_count/DATEDIFF(Second, qs.creation_time, GetDate()) AS 'Llamadas/Segundo',
(qs.total_worker_time/qs.execution_count)/1000000.0 AS 'PromedioTiempoEjecucion(s)',
qs.max_logical_reads AS 'LecturasLogicas', 
qs.max_logical_writes AS 'EscriturasLogicas', 
qs.total_physical_reads AS 'LecturasFisicas',
DATEDIFF(Minute, qs.creation_time, GetDate()) AS 'TiempoCache(min)'
FROM sys.dm_exec_query_stats AS qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) AS qt
WHERE qt.dbid = db_id()
ORDER BY total_logical_reads DESC
Procedimientos almacenados más costosos para el disco (lecturas)
SELECT TOP 20 qt.text AS 'Nombre_SP',
qs.total_physical_reads AS 'TotalLecturasFisicas',
(qs.total_physical_reads/qs.execution_count)/1000000.0 AS 'PromedioLecturasFisicas',
qs.execution_count AS 'NumEjecuciones',
qs.execution_count/DATEDIFF(Second, qs.creation_time, GetDate()) AS 'Llamadas/Segundo',
qs.max_logical_reads AS 'LecturasLogicas', 
qs.max_logical_writes AS 'EscriturasLogicas', 
DATEDIFF(Minute, qs.creation_time, GetDate()) AS 'TiempoCache(min)'
FROM sys.dm_exec_query_stats AS qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) AS qt
WHERE qt.dbid = db_id()
ORDER BY qs.total_physical_reads DESC
Cabe destacar que las consultas están basadas en el uso de las funciones y vistas de administración dinámica (popularmente conocidas como DMV).
Antes de finalizar el artículo, me gustaría mencionar que parte de las consultas han sido obtenidas del blog sqlserverperformance, aunque las he adaptado y modificado para mayor comprensión de los lectores.
¡Enjoy T-SQL!

jueves, 24 de noviembre de 2011

Reducir el tamaño del log de transacciones de todas las bases de datos en SQL Server.

Dándole vueltas a lo que escribí en el post anterior se me ocurrió que podía crear un script para reducir el log de transacciones de todas las bases de datos (en SQL Server 2005 y superior), exceptuando aquellas que son del propio sistema.
El algoritmo se basa en los pasos siguientes:
  1. Recorrer todas las bases de datos que no son de sistema y que tienen el modelo de recuperación en completo o registro de copias masivas (quedan almacenadas en la variable de tabla @tblBD).
  2. Poner las bases de datos que cumplen las condiciones anteriores en modelo de recuperación simple.
  3. Buscar los ficheros que almacenan los registros de transacciones para cada base de datos (quedan almacenados en la tabla temporal #tblLog).
  4. Reducir el espacio de cada uno de los ficheros detectados en el paso anterior (mediante la instrucción DBCC_SHRINKFILE)
  5. Poner el modelo de recuperación de la base de datos al estado original (completo o registro de copias masivas).
Así que me puse manos a la obra, y aquí os lo dejo:
DECLARE @tblBD TABLE
(
  IDAux SMALLINT IDENTITY(1,1), 
  BDID INT,
  BDName VARCHAR(4000),
  RecoveryModel SMALLINT
)

CREATE TABLE #tblLog 
(
  IDRowLog SMALLINT IDENTITY (1,1), 
  LogFilename VARCHAR(4000)
)

DECLARE @intRecoveryModel SMALLINT
DECLARE @intNumTotalBD SMALLINT
DECLARE @intContBD SMALLINT=1
DECLARE @intBDID INT
DECLARE @strBDName VARCHAR(4000)
DECLARE @strSQL AS NVARCHAR(4000)

INSERT INTO @tblBD
SELECT database_id,
  name,
  recovery_model 
FROM sys.databases
WHERE NAME NOT IN ('master','tempdb','model','msdb')
AND recovery_model IN (1,2)

SELECT @intNumTotalBD=COUNT(*) FROM @tblBD

WHILE @intContBD<=@intNumTotalBD
  BEGIN
 SELECT @intBDID=BDID,
   @strBDName=BDName,
   @intRecoveryModel=RecoveryModel
 FROM @tblBD WHERE IDAux=@intContBD
 
 SET @strSQL='ALTER DATABASE '+@strBDName+' SET RECOVERY SIMPLE'
 exec sp_executesql @strSQL
 --PRINT @strsQL
 
 DECLARE @intLogTotal AS SMALLINT
 DECLARE @intPos AS SMALLINT=1
 DECLARE @strLogFile AS VARCHAR(4000)

 INSERT INTO #tblLog (LogFilename)
 SELECT name FROM sys.master_files 
 WHERE database_id=@intBDID AND type=1

 SELECT @intLogTotal=COUNT(*) 
 FROM #tblLog

 WHILE @intPos<=@intLogTotal
   BEGIN
  SELECT @strLogFile=LogFileName 
  FROM #tblLog WHERE IDRowLog=@intPos
  
  SET @strSQL='USE '+@strBDName+' DBCC SHRINKFILE('+@strLogFile+')'
  EXEC sp_executesql @strSQL
  --PRINT @strSQL
  SET @intPos+=1
   END
   TRUNCATE TABLE #tblLog
 IF @intRecoveryModel=1 
   SET @strSQL='ALTER DATABASE '+@strBDName+' SET RECOVERY FULL'
 ELSE 
   SET @strSQL='ALTER DATABASE '+@strBDName+ ' SET RECOVERY BULK_LOGGED'
 
 exec sp_executesql @strSQL
 --PRINT @strSQL
 SET @intContBD+=1
  END
  DROP TABLE #tblLog
Aun así, también existen otras formas de lograr el mismo objetivo, con lo que podéis evaluar la opción que más os guste o entendáis mejor.

¡Enjoy T-SQL!

jueves, 17 de noviembre de 2011

Reducir el tamaño del log de transacciones en SQL Server

Últimamente me he encontrado unas cuantas situaciones en las que me han preguntado cómo reducir el tamaño del log de transacciones en SQL Server 2008 y/o superior, ya que las instrucciones usadas en SQL Server 2000 y SQL Server 2005 usadas para este fin dejaron de estar soportadas.
El script a usar sería el siguiente (en este caso usaremos la base de datos AdventureWorks):
USE AdventureWorks
GO

ALTER DATABASE AdventureWorks 
SET RECOVERY SIMPLE
GO

DBCC SHRINKFILE (AdventureWorks_Log)
GO

ALTER DATABASE AdventureWorks 
SET RECOVERY FULL
GO
Cabe tener en cuenta que en este ejemplo la instrucción DBCC SHRINKFILE reduce el fichero de log al máximo (en el parámetro se le debe indicar el nombre lógico del fichero).
En otro post ya hablaremos el porqué del crecimiento del fichero de log y como se podría evitar.
¡Enjoy T-SQL!

lunes, 7 de noviembre de 2011

Transfiriendo inicios de sesión y contraseñas de SQL Server entre servidores

En cualquier proyecto de migración o de traspaso de bases de datos entre servidores de SQL Server nos encontramos con la problemática de los usuarios huérfanos. Un primer paso para resolver este tipo de incidencia es la transferencia de los inicios de sesión de un servidor hacía otro mediante el uso de la función sp_help_revlogin, el script de la cuál podéis encontrar aquí, si vuesto servidor es un SQL Server 2000, o bien aquí si es un SQL Server 2005.
Mediante la ejecución de este script se generará la función sp_help_revlogin en la base de datos master, que posteriormente deberemos ejecutar (exec sp_help_revlogin) y gracias a la cuál obtendremos en la ventana de resultados el script de generación de todos los inicios de sesión del servidor donde hayamos ejecutado la función. Útil, ¿verdad?




El siguiente paso ya será la asociación entre inicios de sesión y usuarios de las distintas bases de datos, de lo que ya hablaremos en otro post.
¡Enjoy T-SQL!