SQL Server, ideas y experiencias

Cómo permitir el uso del Profiler o la creación de Trazas sin tener derechos de administrador

por Jose Mariano Alvarez 31. julio 2009

La ejecución del SQL Server Profiler requiere al menos del permiso de servidor ALTER TRACE. Este es el mismo permiso que se requiere para poder ejecutar los procedimientos almacenados de T-SQL que se utilizan para crear las trazas.

Veamos un ejemplo.

Creamos un usuario con mínimos permisos :

USE [master]

GO

-- creamos el Login 

CREATE LOGIN [prueba] 

WITH PASSWORD=N'pruebaPass', 

DEFAULT_DATABASE=[master], 

CHECK_EXPIRATION=OFF, CHECK_POLICY=OFF

GO

Luego podemos verificar que no se puede acceder mediante el profiler:

ProfilerPrbPerm

Hacer click en la imagen para agrandarla.

Asignamos el permiso de servidor ALTER TRACE con lo cual le concedemos el permiso de hacer trazas y conectar el Profiler para realizar un seguimiento.

GRANT ALTER TRACE 

TO [Prueba]

GO

Luego nos conectamos desde el Profiler y verificamos que ahora si se puede conectar.

Entonces ejecutamos :

CREATE LOGIN [prueba2] 

WITH PASSWORD=N'pruebaPass', 

DEFAULT_DATABASE=[master], 

CHECK_EXPIRATION=OFF, CHECK_POLICY=OFF

GO

exec sp_help 'sys.indexes'

Como puede verse en la próxima imagen siguiente, el Profiler funciona y como seleccionamos el evento SQL:BatchStarting nos muestra las sentencias que ejecutamos.

CreateLoginEnProfiler

Hacer click en la imagen para agrandarla.

Consideraciones de seguridad importantes al asignar el permiso ALTER TRACE

Es importante ver que en el caso del CREATE LOGIN nos oculta los datos del usuario y la contraseña. Sin embargo nos muestra el parámetro del procedimiento almacenado sp_help.

Como los usuarios que tienen el permiso ALTER TRACE pueden ver las consultas capturadas, se debe tener cuidado ya que las mismas pueden contener datos confidenciales, como contraseñas que se pasan como parámetros en los procedimientos almacenados. El caso mas común es cuando se utilizan mecanismos propietarios de autenticación. Por lo tanto, es importante conceder estos permisos solo a los usuarios que tengan autorización para ver información confidencial.

Tags: , , , ,

Artículos

Usando el Resource Governor - Documento

por Jose Mariano Alvarez 25. julio 2009

CPUPerfGraf Entre las nuevas características que se encuentran en el SQL Server 2008 está el Resource Governor (regulador de recursos), que ofrece la capacidad de vigilar y controlar el uso de CPU y memoria.

Este “White Paper” explica varios escenarios de uso práctico del Resource Governor y ofrece orientación sobre las mejores prácticas para emplearlo de manera eficiente. Se encuentra dirigido a los profesionales de IT y administradores de base de datos responsables de la gestión de los servidores SQL Server 2008. Entre las características que cubre el documento se encuentran la forma de utilizar el Resource Governor tomando en cuenta los requerimientos de concurrencia, de alta disponibilidad, la consolidación, la virtualización, o los acuerdos de nivel de servicio (Service Level Agreement o SLA) para los casos de entornos de producción con SQL Server.

En el documento se destacan varios escenarios de uso común, que pueden ayudar a decidir cuándo y dónde utilizar esta tecnología, y un resumen de las mejores prácticas cuando se utiliza el Resource Governor.

Les dejo el enlace para poder descargar el documento (en inglés) desde el sitio de Microsoft

Using the Resource Governor (DOCX)

Si les interesan los conceptos básicos les dejo un par de links a los libros de ayuda:

Introducción al regulador de recursos

Conceptos del regulador de recursos

Tags: , , , , , ,

Documentos

Como numerar eficientemente las filas de una consulta select

por Jose Mariano Alvarez 10. julio 2009

Uno de las preguntas más frecuentes es cómo numerar la filas de una consulta. En SQL Server 2005 se introdujo ROW_NUMBER() para poder realizar esta operación fácilmente. Sin embargo en los casos en que no la podemos usar como en SQL Server 2000 existen creencias de que los subquery pueden ser alternativas eficientes y las consecuencias suelen ser catastróficas luego de que el volumen de registros crece.

Usando la tabla AdventureWorks2008.Sales.Customer vamos a probar cuatro estrategias y sus consecuencias.

 

Usando un subquery como habitualmente se sugiere en SQL Server 2000

Select  
    (
        select
            COUNT(*) + 1
        from AdventureWorks2008.Sales.Customer B 
        where b.AccountNumber  < a.AccountNumber
    ) as fila, 
    a.*
from AdventureWorks2008.Sales.Customer a
order by rowguid 

El resultado del plan muestra como se anida un SCAN de la tabla dentro de un NESTED LOOP lo cual genera un severo problema de rendimiento.

  |--Compute Scalar(DEFINE:([Expr1006]=[Expr1004]+(1)))
       |--Nested Loops(Inner Join, OUTER REFERENCES:([a].[CustomerID]))
            |--Compute Scalar(DEFINE:([a].[AccountNumber]=[AdventureWorks2008].[Sales].[Customer].[AccountNumber] as [a].[AccountNumber]))
            |    |--Compute Scalar(DEFINE:([a].[AccountNumber]=isnull('AW'+[AdventureWorks2008].[dbo].[ufnLeadingZeros]([AdventureWorks2008].[Sales].[Customer].[CustomerID] as [a].[CustomerID]),'')))
            |         |--Sort(ORDER BY:([a].[rowguid] ASC))
            |              |--Clustered Index Scan(OBJECT:([AdventureWorks2008].[Sales].[Customer].[PK_Customer_CustomerID] AS [a]))
            |--Compute Scalar(DEFINE:([Expr1004]=CONVERT_IMPLICIT(int,[Expr1010],0)))
                 |--Stream Aggregate(DEFINE:([Expr1010]=Count(*)))
                      |--Index Spool(SEEK:([B].[AccountNumber] < isnull('AW'+[AdventureWorks2008].[dbo].[ufnLeadingZeros]([AdventureWorks2008].[Sales].[Customer].[CustomerID] as [a].[CustomerID]),'')))
                           |--Compute Scalar(DEFINE:([B].[AccountNumber]=isnull('AW'+[AdventureWorks2008].[dbo].[ufnLeadingZeros]([AdventureWorks2008].[Sales].[Customer].[CustomerID] as [B].[CustomerID]),'')))
                                |--Index Scan(OBJECT:([AdventureWorks2008].[Sales].[Customer].[IX_Customer_TerritoryID] AS [B]))

 

Si vemos a continuación los detalles de la cantidad de IO podemos ver claramente como la cantidad de lecturas lógicas es de 1103320,

Table 'Worktable'.
    Scan count 19820,
    logical reads 1103320,
    physical reads 0,
    read-ahead reads 0,
    lob logical reads 0,
    lob physical reads 0,
    lob read-ahead reads 0.


Table 'Customer'.
    Scan count 2,
    logical reads 160,
    physical reads 0,
    read-ahead reads 0,
    lob logical reads 0,
    lob physical reads 0,
    lob read-ahead reads 0.

El resultado de la consulta tardo 1 minuto y 37 segundos

 

 

Usando la nueva sintaxis ROW_NUMBER() introducida en SQL Server 2005

Select
       ROW_NUMBER() OVER (ORDER BY a.AccountNumber ) as fila,
       A.* 
from 
       AdventureWorks2008.Sales.Customer a
order by 
       rowguid 

El resultado del plan muestra no se anida en este caso ningún SCAN sino que es un plan secuancial y muy eficiente.

  |--Sort(ORDER BY:([a].[rowguid] ASC))
       |--Sequence Project(DEFINE:([Expr1002]=row_number))
            |--Segment
                 |--Compute Scalar(DEFINE:([a].[AccountNumber]=[AdventureWorks2008].[Sales].[Customer].[AccountNumber] as [a].[AccountNumber]))
                      |--Sort(ORDER BY:([a].[AccountNumber] ASC))
                           |--Compute Scalar(DEFINE:([a].[AccountNumber]=isnull('AW'+[AdventureWorks2008].[dbo].[ufnLeadingZeros]([AdventureWorks2008].[Sales].[Customer].[CustomerID] as [a].[CustomerID]),'')))
                                |--Clustered Index Scan(OBJECT:([AdventureWorks2008].[Sales].[Customer].[PK_Customer_CustomerID] AS [a]))

 

Vemos como el resultado de aplicar la nueva función ha cambiado y solo se realizan 123 lecturas lógicas.

Table 'Customer'.
    Scan count 1,
    logical reads 123,
    physical reads 0,
    read-ahead reads 0,
    lob logical reads 0,
    lob physical reads 0,
    lob read-ahead reads 0.

 El resultado de la consulta tardo 1 segundo.

 

 

Usando la función IDENTITY() como en SQL Server 2000

En este caso se debe recurrir a una tabla temporal pero vemos que el beneficio es sustancial.

Debido a lo que ocurre con la función IDENTITY() y el ORDER BY se debe crear una tabla temporal para insertar los registros. Les dejo el Enlace a “The behavior of the IDENTITY function when used with SELECT INTO or INSERT .. SELECT queries that contain an ORDER BY clause”.

http://support.microsoft.com/kb/273586

NOTA: Quiero agradecer a Alejandro Mesa quien me hizo el comentario del error en los foros respecto de este comportamiento que yo había omitido en el Post el cual ya se encuentra actualizado y corregido según la documentacióní.

Creamos la tabla temporal para ordenar los registros

CREATE TABLE [dbo].[#Clientes](
    [fila] [int] IDENTITY(1,1) NOT NULL,
    [CustomerID] [int] NULL,
    [PersonID] [int] NULL,
    [StoreID] [int] NULL,
    [TerritoryID] [int] NULL,
    [AccountNumber] [varchar](10) NOT NULL,
    [rowguid] [uniqueidentifier] NOT NULL,
    [ModifiedDate] [datetime] NOT NULL
) ON [PRIMARY]
GO

 

Esta es la parte de la consulta donde se generan los números de fila.

Insert into #Clientes
(
    CustomerID, 
    PersonID, 
    StoreID, 
    TerritoryID, 
    AccountNumber, 
    rowguid, 
    ModifiedDate
)
Select     
    cast(CustomerID as int) as CustomerID , 
    PersonID, 
    StoreID, 
    TerritoryID, 
    AccountNumber, 
    rowguid, 
    ModifiedDate
from AdventureWorks2008.Sales.Customer a
ORDER BY a.AccountNumber 

Ahora vemos nuevamente que no se anida un SCAN en el plan por lo que resulta mucho más eficiente que en el caso del subquery.

  |--Table Insert(OBJECT:([#Clientes]), SET:([#Clientes].[CustomerID] = [Expr1006],[#Clientes].[PersonID] = [AdventureWorks2008].[Sales].[Customer].[PersonID] as [a].[PersonID],[#Clientes].[StoreID] = [AdventureWorks2008].[Sales].[Customer].[StoreID] as [a
       |--Compute Scalar(DEFINE:([Expr1007]=getidentity((-7),(0),N'#Clientes')))
            |--Top(ROWCOUNT est 0)
                 |--Compute Scalar(DEFINE:([a].[AccountNumber]=[AdventureWorks2008].[Sales].[Customer].[AccountNumber] as [a].[AccountNumber], [Expr1006]=CONVERT(int,[AdventureWorks2008].[Sales].[Customer].[CustomerID] as [a].[CustomerID],0)))
                      |--Sort(ORDER BY:([a].[AccountNumber] ASC))
                           |--Compute Scalar(DEFINE:([a].[AccountNumber]=isnull('AW'+[AdventureWorks2008].[dbo].[ufnLeadingZeros]([AdventureWorks2008].[Sales].[Customer].[CustomerID] as [a].[CustomerID]),'')))
                                |--Clustered Index Scan(OBJECT:([AdventureWorks2008].[Sales].[Customer].[PK_Customer_CustomerID] AS [a]))

 

Si vemos los resultados en I/O solo se realizan 123 lecturas logicas

Table 'Customer'.
    Scan count 1,
    logical reads 123,
    physical reads 0,
    read-ahead reads 0,
    lob logical reads 0,
    lob physical reads 0,
    lob read-ahead reads 0.

Select * 
from #Clientes c
order by C.rowguid 

El plan de esta parte es el SCAN y el SORT.

|--Sort(ORDER BY:([c].[rowguid] ASC))
       |--Table Scan(OBJECT:([tempdb].[dbo].[#Clientes] AS [c]))

 

Si vemos los resultados en I/O solo se realizan 167 lecturas logicas

Table '#Clientes_000000000007'.
    Scan count 1,
    logical reads 167,
    physical reads 0,
    read-ahead reads 0,
    lob logical reads 0,
    lob physical reads 0,
    lob read-ahead reads 0.

Queda eliminar la tabla temporal con

drop table #Clientes 

El total acumulado de tiempo fue de 1 segundo.

 

 

Conclusión:

 

Caso Lecturas Tiempo
Subquery 1103480 97 seg
Row_Number() 123 1 seg
Tabla temporal + Identity() 280 1 seg

Vemos que es mucho más eficiente la tercera opción usando una tabla temporal y la función identiy() que la opción de la subquery (subconsulta). Sin embargo esta no es  tan eficiente como en el caso de la nueva sintaxis de SQL Server 2005/8 con ROW_NUMBER(). Por lo tanto si tiene SQL Server 2005 o SQL Server 2008 Lo mejor es usar la funcion ROW_NUMBER() y si tienen SQL Server 2000 la mejor opción es usar la tabla temporal y la función Identity().

 

En todos los casos todas las lecturas fueron lógicas ya que la tabla tenia todas las paginas en memoria.

NOTA: Me falta comparar la alternativa de usar CLR y de usar un cursor de T-Sql.

Tags: , , ,

Artículos

Buenas prácticas en el uso de índices - La selectividad

por Jose Mariano Alvarez 16. mayo 2009

Introducción

Los índices mejoran el rendimiento de las consultas que seleccionan un pequeño porcentaje de las filas de una tabla. La selectividad de los índices es uno de los conceptos más importantes a la hora de entender si un índice puede ser útil en esos casos. Para comprender el concepto, vamos a analizar las consecuencias de la selectividad de un índice no agrupado (NON CLUSTERED) sobre una columna de una tabla de la base de datos de ejemplo AdventureWorks que tiene el SQL Server 2008. Los accesos puntuales, que es lo que vamos a analizar en este caso, no son la única utilidad que nos ofrecen los índices para mejorar los costos, pero es importante comprender por qué en ocasiones no se utilizan índices existentes.

La motivación

Uno de las características fundamentales del SQL Server 2008 (y versiones anteriores también) es que la selección de las estrategias de ejecución del motor relacional se encuentran basadas en los costos. De esta manera cobra vital importancia la creación de índices para reducir estos costos.

Cuando creamos índices una de las posibles utilidades que ofrecen es reducir la carga impuesta a la base de datos permitiendo accesos puntuales a los registros a partir del índice lo que habitualmente se conoce como INDEX SEEK, para luego acceder en un segundo paso a los registros de la tabla. Si no existe el índice, en lugar de que el motor de la base de datos pueda acceder puntualmente, tiene que explorar todos los registros de la tabla o índice agrupado, lo que se conoce como TABLE SCAN o CLUSTER INDEX SCAN.

Ambas estrategias de acceso tienen sus costos. Por lo tanto la selección que hace el motor de la base de datos deberá estar de acuerdo a los costos. Además, cada una de las estrategias tiene sus consecuencias.

Si tenemos índices que no se utilizan simplemente estaríamos aumentando el trabajo que tiene que realizar el SQL Server para mantener actualizados los índices cuando se realizan modificaciones y estaríamos aumentando el espacio de almacenamiento usado por guardar las estructuras de los índices tanto en memoria como en disco. Por lo tanto es importante entender algunos conceptos importantes para crear buenos índices.

La selectividad

Vamos a definir la selectividad de un índice, como el porcentaje promedio de filas en una tabla que tienen el mismo valor en las columnas involucradas en el índice, esto equivale al cociente (ratio) entre el número de valores distintos en las columnas que definen el índice y el número de registros en la tabla. La selectividad ideal es 1 y representa el caso en que todas las entradas del índice son únicas. Esta selectividad puede ser garantizada sólo por índices únicos. SQL Server crea automáticamente índices en las columnas de todas las restricciones de integridad de clave primaria (PRIMARY KEY) y únicas (UNIQUE) que de definen. Esto ocurre porque generalmente estos índices son los más selectivos y más eficientes para optimizar el rendimiento ya que permiten seleccionar al motor de la base de datos estrategias particulares.

Ecuacion densidad

Quizá sea más simple comprender el inverso multiplicativo de la selectividad que representa el promedio de filas de igual valor que se van a obtener en el caso de que exista un condición por igualdad en la clausula WHERE de la sentencia.

ecuacion promedio de valores iguales

Veamos un simple ejemplo en la base de datos AdventureWorks de nuestro SQL Server 2008.

USE AdventureWorks

GO

SELECT COUNT (DISTINCT ProductID) FROM Sales.SalesOrderDetail

266

SELECT COUNT(*) FROM Sales.SalesOrderDetail

121317

Por lo tanto vemos que la selectividad de nuestro índice por la columna ProductID es 266/121317 0.002192602 lo que representa una selectividad regular ya que nuestro ideal es 1. Si vemos el inverso multiplicativo, lo que equivale a hacer121317/266 obtenemos 456.07 que representa el número promedio de registros cuando buscamos las filas de un producto en nuestra tabla de detalle de órdenes.

Veamos las consecuencias a la hora de realizar consultas.

Ejemplo 1

SELECT * FROM Sales.SalesOrderDetail WHERE productID = 870

El plan resultante es el siguiente

Selectividad1

Como podemos ver el plan refleja el hecho de que existen muchos registros con el productID = 870 y por lo tanto le resulta más eficiente realizar en SCAN. La selectividad de la condición no es adecuada para un acceso puntual.

Ejemplo 2

SELECT * FROM Sales.SalesOrderDetail WHERE productID = 719

El plan resultante es el siguiente

Selectividad2

En este caso el SQL Server elige realizar un SEEK del índice NON CLUSTERED porque determina que es más eficiente. Luego debe realizar un KEY LOOKUP para obtener el resto de las columnas que no se encuentran en el índice. Si comparamos estos dos casos podemos ver claramente que a diferentes valores de productID, el SQL Server determina en cual es el mejor método de acceso analizando la selectividad de cada valor de productID en particular.

Ejemplo 3

DECLARE @ProdId INT

SET @ProdId = 719

SELECT * FROM Sales.SalesOrderDetail WHERE productID = @ProdId

El plan resultante es el siguiente

Selectividad3

En este ejemplo vemos que a pesar de que el valor es el mismo del ejemplo anterior, debido al uso de la variable no puede conocer el valor específico al momento de compilar y optimizar, y por lo tanto utiliza el caso promedio que corresponde a la selectividad promedio y por lo tanto realiza un SCAN independientemente del valor de la variable.

Vamos a dejar para otro artículo el tema de los parámetros de los procedimientos almacenados ya que requiere un análisis particular.

La densidad

Si buscamos en la documentación del SQL Server encontramos que el comando DBCC SHOW_STATISTICS nos permite ver la información estadística usada para seleccionar el plan de ejecución. Dentro de esta información se encuentran las densidades y un histograma disponible para la primera columna del índice. Esta fue la información que permitió determinar los planes de ejecución en los ejemplos anteriores.

La densidad se define como:

Ecuacion Densidad

Por lo tanto si multiplicamos la densidad por la cantidad de registros de la tabla obtenemos el promedio de valores iguales o el inverso multiplicativo de la selectividad.

DBCC SHOW_STATISTICS ( 'Sales.SalesOrderDetail' , 'IX_SalesOrderDetail_ProductID')

Dentro de la información que nos presenta está:

 

All density

Average Length

Columns

0,003759399

4

ProductID

8,242868E-06

8

ProductID, SalesOrderID

8,242868E-06

12

ProductID, SalesOrderID, SalesOrderDetailID

Si multiplicamos por la cantidad de filas de la tabla obtenemos 0, 003759399 * 121317 = 456,07 que es el mismo valor que antes.

Conclusión

Un índice puede ser selectivo de acuerdo al valor utilizado. Si el índice no es selectivo, el SQL Server no lo va a utilizar para acceder a los registros mediante un SEEK y va a preferir realizar un TABLE SCAN. No tiene sentido crear índices para acceder puntualmente a un subconjunto de registros de la tabla en el caso de no ser selectivos. Existen otros motivos para crear índices como cover index que justifican en algunos casos índices no tan selectivos.

Tags: , , ,

Artículos

Como reducir y truncar el Log de Transacciones

por Jose Mariano Alvarez 4. abril 2009

Introducción

Uno de los problemas recurrentes y más comunes es el reducir el tamaño del archivo del log de transacciones (transaction log) cuyo crecimiento desmedido en general se produce debido al desconocimiento de la función que cumple y que debe hacerse para que no ocurra.

La función del log de transacciones

En el SQL server el log de transacciones cumple un rol importante y es el de garantizar la integridad de la base de datos. Antes de que las modificaciones realizadas por un usuario en la base de datos sean escritas en alguno de los archivos de datos (archivos MDF y NDF), se realiza la escritura en el log de transacciones (archivos LDF). Las modificaciones son confirmadas al cliente como terminadas (commit de la transacción) cuando la escritura en el log de transacciones se completa aunque las páginas de datos aun permanezcan en memoria y no hayan sido grabadas en los correspondientes archivos de datos. Esto provoca que ante una falla sea necesario recurrir al log de transacciones para recuperar la base de datos porque allí es el único lugar donde se encuentra la información de las modificaciones. Por lo tanto, NO SE DEBE forzar al SQL Server a construir un nuevo archivo de log de transacciones parando el servicio del SQL Server para borrar el log de transacciones desde el sistema operativo.

Solución a problemas

Si el log de transacciones ha crecido es porque SQL Server ha precisado espacio adicional para garantizar que pueda recuperarse ante una falla del disco de datos. Por lo tanto existen varias estrategias básicas una vez que se ha llegado a este punto:

  1. Truncar el log de transacciones, lo que significa hacer un backup de log de las entradas correspondientes a las modificaciones realizadas y así reutilizar el espacio del log de transacciones. El SQl Server usa una estrategia de estructura de datos en añillo para reutilizar el log de transacciones. Luego usar una de las siguientes opciones:
    • Mantener el espacio ocupado por el archivo del log de transacciones.
    • Reducir el archivo del log de transacciones porque ha crecido demasiado.
  2. Dejar seguir creciendo el log de transacciones.
  3. No utilizar el log de transacciones para garantizar la recuperación sino únicamente para la integridad de cada transacción y hacer que lo trunque automáticamente al teminar la misma. El tamaño en este caso no crece a menos que haya alguna transacción que no quepa en el log de transacciones actual. Luego usar una de las siguientes opciones:
    • Mantener el espacio ocupado por el archivo del log de transacciones.
    • Reducir el archivo del log de transacciones porque ha crecido demasiado.

Aquí entran en juego los modelos de recuperación de las bases de datos

  • En el modelo de recuperación Full la modificaciones permanecen en los archivos del log de transacciones hasta que se hace un backup del log de transacciones,  luego del backup el espacio de log de transacciones no activas respaldadas puede reutilizarse.
  • En el modelo de recuperación simple, las modificaciones son marcadas automaticamente como completadas en el log de transacciones y el espacio puede reutilizarse.

Por lo tanto es importante tener bien claro que el Backup de las bases de datos NO TRUNCA el log de transacciones pero el backup del log de transacciones SI LO PUEDE HACER.

Por lo tanto para mantener el tamaño del log de transacciones bajo control y para garantizar la recuperabilidad es recomendable realizar el backup del log de transacciones frecuentemente.

 

Ejemplos y alternativas para truncar el log de transacciones.

Se debe tener en cuenta que estas son acciones correctivas y solo deben ser realizadas por única vez. El backup periódico del log de transacciones es la manera correcta de mantener el log de transaciones bajo control.

Ejemplo 1: Usando el backup del log de transacciones:

BACKUP LOG [AdventureWorks] 

TO DISK = N'C:\Backup\AdventureWorks.bak' 
WITH NOFORMAT, NOINIT, 
NAME = N'AdventureWorks-Transaction Log Backup', 
SKIP, NOREWIND, NOUNLOAD, STATS = 10 

Ejemplo 2: Pasar la base de datos temporariamente de full a simple para forzar el truncado del log de transacciones. Es recomendable realizar esta operacion en single user para evitar que haya posibles transacciones de otros usurios durante el tiempo que la base de datos esta en modo simple y no permanezcan respaldados en el log de transacciones definitivo. Es recomendable realizar un backup de la base de datos para garantizar la recuperabilidad.

USE [master] 
GO 

ALTER DATABASE [AdventureWorks] SET RECOVERY SIMPLE WITH NO_WAIT 
GO 
ALTER DATABASE [AdventureWorks] SET RECOVERY SIMPLE 
GO 

CHECKPOINT 
GO 
CHECKPOINT 
GO 

ALTER DATABASE [AdventureWorks] SET RECOVERY FULL WITH NO_WAIT 
GO 
ALTER DATABASE [AdventureWorks] SET RECOVERY FULL 
GO

 

La recomendación general es:

  • Utilizar una estrategia de backup que realice BACKUP FULL de la base de datos con Backup del log de transacciones periódicamente.
  • No borrar el log de transacciones manualmente salvo una causa de fuerza mayor

 

Como reducir el tamaño del archivo del log de transacciones

Hasta ahora solo logramos truncar el log de transacciones pero no reducir el tamaño del archivo. Al ejecutar DBCC SHRINKFILE le indicamos al SQL Server que queremos reducir el tamaño físico del archivo, en nuestro caso podemos hacerlo sobre los archivos fisicos que componen el del log de transacciones.

Importante: Solo se podrá truncar la parte inactiva del log de transacciones.

 

Más información en el sitio de microsoft

Truncación del registro de transacciones

Reducir el registro de transacciones

Cómo detener el crecimiento inesperado del registro de transacciones de una base de datos de SQL Server

Tags: , , ,

Artículos

Documento - SQL Server Consolidation at Microsoft

por Jose Mariano Alvarez 1. abril 2009

Para aquellos que estén pensando en consolidar sus servidores SQL, este whitepaper de Microsoft IT les puede resultar de interés. Encara el tema desde el punto de vista de la consolidación de hosts, de instancias y de bases de datos.

Revisa el despliegue de SQL Utility en Microsoft, las decisiones que hizo, los detalles de la ejecución, y los aspectos de la calidad del sistema.

Está orientado a los encargados de adoptar decisiones técnicas y familiarizados con las tecnologías de Windows Server y SQL Server para servir como orientación. Cada entorno debe adaptar las lecciones aprendidas para satisfacer sus necesidades específicas.

Un tema incluido también es la virtualización ya que es una solución muy interesante para aplicar en este tema.

SQL Server Consolidation at Microsoft

Tags: ,

Documentos

Implementiando “SQL Server Fast Track Data Warehouse”

por Jose Mariano Alvarez 7. marzo 2009

El paper define un modelo de configuración de referencia conocido como “SQL Server Fast Track Data Warehouse” y una aproximación para un multiprocesador simétrico basado en las expectativas de rendimiento y escalabilidad para el tratamiento de cargas de trabajo de I/O secuencial.

El propósito del documento es definir un enfoque arquitectónico repetible para implementar un modelo escalable de data warehouse en SQL Server 2008 en un multiprocesador simétrico (SMP).

El resultado final de este proceso representa el mínimo recomendado e incluye todo el software y el hardware necesarios para alcanzar y mantener un nivel básico de rendimiento escalable tomando en cuenta la carga secuencial de E/S clásica de escenarios de data warehouse en lugar de la carga de trabajo tradicional de E/S al azar de los OLTP.

mplementing a SQL Server Fast Track Data Warehouse

Tags: , , , ,

Artículos | Documentos

Powered by SQL Total Consulting


View Jose Mariano Alvarez's profile on LinkedIn

 Add to Technorati Favorites 

Calendar

<<  junio 2017  >>
lumamijuvido
2930311234
567891011
12131415161718
19202122232425
262728293012
3456789

View posts in large calendar

Locations of visitors to this page

Widget Twitter not found.

Root element is missing.X


Valid XHTML 1.0 Transitional

Valid CSS!