Utilidades de Sql Server con ADO.NET – Diagnosticar y Reparar Tablas

Hola ¿Qué tal?…

Continuando con la serie de utilidades de Sql Server con ADO.NET, llega a escena una herramienta que nos proporcionará diagnósticos y reparaciones de nuestras tablas, utilizando el mismo DBCC (Database Command Console) de T-SQL, realizaremos un método en la clase que creamos en la publicación anterior llamada SqlUtilities.

Reparar y Diagnosticar las Tablas de una Base de Datos de SQL Server con T-SQL

Para el diagnóstico y reparación de las tablas de nuestra base de datos utilizaremos la instrucción DBCC CHECKTABLE, en la publicación anterior checamos los campos identity de una tabla, con la instrucción DBCC CHECKIDENT, el cual repara la congruencia de la semilla que da los números automáticamente a los campos Identity y además permite regenerar el contador en caso necesario. En esta ocasión nos vamos un poco más arriba y veremos cómo reparar y diagnosticar nuestras tablas, además de que generaremos un archivo de reporte de los resultados obtenidos. En este caso DBCC CHECKTABLE comprobará la integridad de todas las páginas y estructuras de las que se constituye una tabla o una vista indizada.

Primeramente veremos la instrucción de T-SQL, cómo se usa y los parámetros que ocupa. En el siguiente ejemplo muestro los usos de CHECKTABLE utilizando T-SQL.

– Resume el diagnóstico de la tabla
DBCC CHECKTABLE (‘Production.Product’)

– Intenta reparar la tabla con el riesgo de perder datos
DBCC CHECKTABLE (‘Production.Product’,REPAIR_ALLOW_DATA_LOSS)

– Repara la tabla sin el riesgo de perder datos
DBCC CHECKTABLE (‘Production.Product’,REPAIR_REBUILD)

La primera instrucción devuelve un mensaje como el siguiene:

DBCC results for ‘Production.Product’.
There are 504 rows in 13 pages for object “Production.Product”.
DBCC execution completed.
If DBCC printed error messages, contact your system administrator.

Es importante mencionar que las últimas dos instrucciones solo se pueden realizar con la base de datos en modo de usuario único (single user mode). Esto implica que habrá que tener cuidado del uso de estas instrucciones, ya que solo deben utilizarse cuando se sospecha que la tabla tiene fallas en su estructura.  Siempre será mejor restaurar la base de datos en caso de que el diagnóstico devuelva errores en la tabla, el uso de las opciones de reparación es solo en caso de que no se cuente con un respaldo, así que si las reparaciones se aplican correctamente, será recomendable realizar un respaldo de la base de datos inmediatamente después de quedar reparada la tabla. Esta utilería pretende ser para diagnóstico más que para usarla como reparación, sin embargo ampliaremos la funcionalidad para tener herramientas que nos sirvan en casos extremos.

Diagnosticar y Reparar una Tabla de una Base de Datos de SQL Server con ADO.NET

Una vez identificado el uso de las instrucciones de DBCC CHECKTABLE en T-SQL, podremos realizar los métodos para la ejecución de estas instrucciones.

Será muy simple la manera de programar el método de diagnóstico ya que es análogo a lo que hicimos en la primera publicación de esta serie. Veamos cómo queda:

VB.NET

Public Sub CheckTable(ByVal Table As String)
    ‘Se declaran la variables a utilizar
    Dim cmd As SqlCommand = New SqlCommand(“DBCC CHECKTABLE (@Table)”)

    ‘Se agregan el parámetro @Table para identificar la tabla
    cmd.Parameters.Add(“@Table”, _
            SqlDbType.VarChar, 150).Value = Table
    ‘Se asigna la conexión al command
    cmd.Connection = cnn
    ‘Se intentará la ejecución del código
    Try
        ‘Se abre la conexión
        cnn.Open()
        ‘Se ejecuta la instrucción
        cmd.ExecuteNonQuery()
    Catch ex As Exception
        ‘Se capturan los mensajes de error
        mMessages = ex.Message
    Finally
        ‘se cierra la conexión
        cnn.Close()
    End Try
End
Sub

C#

public void CheckTable(string Table)
{
    //Se declaran la variables a utilizar
    SqlCommand cmd =
        new SqlCommand(“DBCC CHECKTABLE (@Table)”);

    //Se agregan el parámetro @Table para identificar la tabla
    cmd.Parameters.Add(“@Table”,
        SqlDbType.VarChar, 150).Value = Table;
    //Se asigna la conexión al command
    cmd.Connection = cnn;

    //Se intentará la ejecución del código
    try
    {
        //Se abre la conexión
        cnn.Open();
        //Se ejecuta la instrucción
        cmd.ExecuteNonQuery();
    }
    catch (SqlException ex)
    {
        //Se capturan los mensajes de error
        messages = ex.Message;
    }
    finally
    {
        //se cierra la conexión
        cnn.Close();
    }
}

El otro método, el cual servirá para realizar la reparación dependerá primeramente de un enumerador que definiremos fuera de la clase SqlUtilities. Este enumerador servirá para enumerar  las opciones de reparación con las que se contará. Así pues, definamos el enumerador, el cual se muestra en el siguiente ejemplo:

VB.NET

Public Enum RepairOption
    REPAIR_ALLOW_DATA_LOSS
    REPAIR_REBUILD
End Enum

C#

public enum RepairOption
{
    REPAIR_ALLOW_DATA_LOSS,
    REPAIR_REBUILD
}

Este enumerador lo utilizaremos en la definición del método de reparación. Este método será una sobrecarga del que se expone más arriba. La definición será prácticamente la misma, solo tendrá un parámetro adicional del tipo RepairOption que es el enumerador que hemos definido. Este enumerador lo utilizaremos en una siguiente publicación.

En el siguiente ejemplo se muestra cómo queda el método de reparación:

VB.NET

Public Sub CheckTable(ByVal Table As String, _
                      ByVal RepairOption As RepairOption)
    ‘Se declaran la variables a utilizar
    Dim cmd As SqlCommand = _
        New SqlCommand(“DBCC CHECKTABLE (@Table , “ & _
                        RepairOption.ToString() & “)”)
    ‘Se agregan el parámetro @Table para identificar la tabla
    cmd.Parameters.Add(“@Table”, _
            SqlDbType.VarChar, 150).Value = Table
    ‘Se asigna la conexión al command
    cmd.Connection = cnn
    ‘Se intentará la ejecución del código
    Try
        ‘Se abre la conexión
        cnn.Open()
        ‘Se ejecuta la instrucción
        cmd.ExecuteNonQuery()
    Catch ex As Exception
        ‘Se capturan los mensajes de error
        mMessages = ex.Message
    Finally
        ‘se cierra la conexión
        cnn.Close()
    End Try
End
Sub

C#

public void CheckTable(string Table, RepairOption RepairOption)
{
    //Se declaran la variables a utilizar
    SqlCommand cmd =
        new SqlCommand(“DBCC CHECKTABLE (@Table, “ +
                        RepairOption.ToString() + “)”);
    //Se agregan el parámetro @Table para identificar la tabla
    cmd.Parameters.Add(“@Table”,
        SqlDbType.VarChar, 150).Value = Table;
    //Se asigna la conexión al command
    cmd.Connection = cnn;
    //Se intentará la ejecución del código
    try
    {
        //Se abre la conexión
        cnn.Open();
        //Se ejecuta la instrucción
        cmd.ExecuteNonQuery();
    }
    catch (SqlException ex)
    {
        //Se capturan los mensajes de error
        messages = ex.Message;
    }
    finally
    {
        //se cierra la conexión
        cnn.Close();
    }
}

Aquí debemos tener en cuenta dos aspectos, el primero es un “trucazo” para utilizar el parámetro RepairOption sin usar un switch (Select Case en VB.NET) y usar directamente el valor del enumerador en la cadena de consulta, por eso es necesario declarar el enumerador con sus miembros textualmente idénticos a los que se utilizan en T-SQL al pasar los parámetros de reparación. Se usa la variable del tipo RepairOption y se invoca el método ToString() con el que se obtiene el nombre del identificador del valor del enumerador. El segundo aspecto es que no podrémos utilizar este método directamente sin antes haber cambiado la opción de acceso de la base de datos a Single_User, lo cual motiva la siguiente publicación.

Utilización del Método

Bien, aquí están los ejemplos de dos posibles usos:

VB.NET

Uso para diagnóstico:

‘Declaramos nuestra variable del tipo SqlUtilties
Dim sqlUtil As SqlUtilities = _
    New SqlUtilities(“(LOCAL)”, “AdventureWorks”, “”, “”)

‘Ejecutamos el método de diagnóstico       
sqlUtil.CheckTable(“Production.Product”)

‘Mostramos el resultado obtenido
MessageBox.Show(sqlUtil.Messages, “Resultados”, MessageBoxButtons.OK)

Uso para reparación:

‘Declaramos nuestra variable del tipo SqlUtilties
Dim sqlUtil As SqlUtilities = _
    New SqlUtilities(“(LOCAL)”, “AdventureWorks”, “”, “”)

‘Para reparar necesitamos cambiar la opción
‘de la base de datos a Sigle User
sqlUtil.ChangeDbUserAccessOption(DBUserAccessOption.SINGLE_USER)

If sqlUtil.GetCurrentDbUserAccessOption().Trim() = “SINGLE_USER” Then
    ‘Ejecutamos el método de Reparación
    sqlUtil.CheckTable(“Production.Product”, _
                        RepairOption.REPAIR_REBUILD)
Else
    MessageBox.Show(“La base de datos debe estar en Single User”, _
                    “Resultados”, MessageBoxButtons.OK)
End If

‘Mostramos el resultado obtenido
MessageBox.Show(sqlUtil.Messages, “Resultados”, MessageBoxButtons.OK)
‘Regresamos la opción de la base de datos
‘MULTI_USER

C#

Uso para diagnóstico:

//Declaramos nuestra variable del tipo SqlUtilties
SqlUtilities sqlUtil =
    new SqlUtilities(“(LOCAL)”, “VentasWeb”, “”, “”);
//Ejecutamos el método de diagnóstico
sqlUtil.CheckTable(“Production.Product”);
//Mostramos el resultado obtenido
MessageBox.Show(sqlUtil.Messages);

Uso para reparación:

//Declaramos nuestra variable del tipo SqlUtilties
SqlUtilities sqlUtil =
    new SqlUtilities(“(LOCAL)”, “AdventureWorks”, “”, “”);
//Para reparar necesitamos cambiar la opción
//de la base de datos a Sigle User
sqlUtil.ChangeDbUserAccessOption(DBUserAccessOption.SINGLE_USER);
if (sqlUtil.GetCurrentDbUserAccessOption().Trim() == “SINGLE_USER”)
{
    //Ejecutamos el método de Reparación       
    sqlUtil.CheckTable(“Production.Product”,
                        RepairOption.REPAIR_REBUILD);
}
else
{
    MessageBox.Show(“La base de datos debe estar en Single User”,
                    “Resultados”, MessageBoxButtons.OK);
}
//Mostramos el resultado obtenido
MessageBox.Show(sqlUtil.Messages);

Conclusiones

Hemos visto varias cosas nuevas aquí, y algunas contradicciones. Sobre las contradicciones quiero comentarles que puede verse contradictorio en algunas líneas de código el uso de concatenación de instrucciones cuando en la publicación en la que hablo de parámetros sugiero sobre todo el uso de parámetros en lugar de la concatenación. Bueno, en el caso de Alter Table fue necesario ya que no se puede utilizar un parámetro para indicar el nombre de la base de datos, también utilicé la concatenación para indicar los parámetros de algunas instrucciones DBCC, bien, cómo es que esto es válido a pesar de todo. Primeramente, la inyección de SQL no es posible en este medio ya que el nombre de la base de datos se toma de las propiedades de la conexión, si el nombre viene más la conexión hacia la base de datos no es posible, por otra parte, los parámetros se toman de los nombres de miembros de un enumerador fijo, por esta razón podemos decir que la concatenación es segura.

Por otra parte es claro que esta utilidad es muy delicada, debemos tener en cuenta que antes que reparar una tabla, debemos tomar el diagnóstico, y si marca errores, siempre será mejor restaurar un respaldo de la base de datos que intentar corregir la tabla.

Referencias de la Publicación

Esta publicación forma parte de la Serie 2 de la colección Utilidades de SQL Server con ADO.NET

Indice de publicaciones que conforman la Serie II:

Serie II Parte I: Diagnosticar y Reparar Tablas de una Base de Datos (http://msmvps.com/blogs/otelis/archive/2007/06/22/utilidades-de-sql-server-con-ado-net-diagnosticar-y-reparar-tablas.aspx)

Serie II Parte II: Cambiar la opción de acceso de una base de datos (http://msmvps.com/blogs/otelis/archive/2007/07/02/utilidades-de-sql-server-con-ado-net-cambiar-la-opci-243-n-de-acceso-de-una-base-de-datos.aspx)

Serie II Parte III: Consultar la opción de acceso de una base de datos (http://msmvps.com/blogs/otelis/archive/2007/07/02/utilidades-de-sql-server-con-ado-net-consultar-la-opci-243-n-de-acceso-de-una-base-de-datos.aspx)

Referencias Adicionales

Con esto terminamos nuestro recorrido por esta utilidad, si tienes alguna duda o comentario no dudes en dejarme tus comentarios. Las referencias de este tema las pongo a continuación:

DBCC CHECKTABLE
http://msdn2.microsoft.com/en-us/library/ms174338.aspx

ALTER TABLE
http://msdn2.microsoft.com/en-us/library/ms190273.aspx

sys.databases
http://msdn2.microsoft.com/en-us/library/ms178534.aspx

La Clase SqlUtilities
http://msmvps.com/blogs/otelis/archive/2007/06/19/utilidades-de-sql-server-con-ado-net-regenerar-campos-identity.aspx

Bien, pues espero que sea de utilidad.

Saludos…

Octavio Telis

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>