Como defragmentar indices en GeneXus X.


Ahora que las bases de conocimiento no estan mas en ctree, no se puede correr un rebuild de los indices, como haciamos antes, sino que hay que hacerlo con SQL server.

Una forma facil de hacerlo (sacado de los Books Online de SQL Server 2005) es ejecutar el siguiente script, que lo que hace es defragmentar todos los índices que tengan una fragmentacion mayor al 30% (es la variable @maxfrag que se puede variar a gusto).


/*Perform a 'USE ' to select the database in which to run the script.*/

-- Declare variables
SET NOCOUNT ON;
DECLARE @tablename varchar(128);
DECLARE @execstr varchar(255);
DECLARE @objectid int;
DECLARE @indexid int;
DECLARE @frag decimal;
DECLARE @maxfrag decimal;

-- Decide on the maximum fragmentation to allow for.
SELECT @maxfrag = 30.0;

-- Declare a cursor.
DECLARE tables CURSOR FOR
SELECT TABLE_NAME
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_TYPE = 'BASE TABLE';

-- Create the table.
CREATE TABLE #fraglist (
ObjectName char(255),
ObjectId int,
IndexName char(255),
IndexId int,
Lvl int,
CountPages int,
CountRows int,
MinRecSize int,
MaxRecSize int,
AvgRecSize int,
ForRecCount int,
Extents int,
ExtentSwitches int,
AvgFreeBytes int,
AvgPageDensity int,
ScanDensity decimal,
BestCount int,
ActualCount int,
LogicalFrag decimal,
ExtentFrag decimal);

-- Open the cursor.
OPEN tables;

-- Loop through all the tables in the database.
FETCH NEXT
FROM tables
INTO @tablename;

WHILE @@FETCH_STATUS = 0
BEGIN;
-- Do the showcontig of all indexes of the table
INSERT INTO #fraglist
EXEC ('DBCC SHOWCONTIG (''' + @tablename + ''')
WITH FAST, TABLERESULTS, ALL_INDEXES, NO_INFOMSGS');
FETCH NEXT
FROM tables
INTO @tablename;
END;

-- Close and deallocate the cursor.
CLOSE tables;
DEALLOCATE tables;

-- Declare the cursor for the list of indexes to be defragged.
DECLARE indexes CURSOR FOR
SELECT ObjectName, ObjectId, IndexId, LogicalFrag
FROM #fraglist
WHERE LogicalFrag >= @maxfrag
AND INDEXPROPERTY (ObjectId, IndexName, 'IndexDepth') > 0;

-- Open the cursor.
OPEN indexes;

-- Loop through the indexes.
FETCH NEXT
FROM indexes
INTO @tablename, @objectid, @indexid, @frag;

WHILE @@FETCH_STATUS = 0
BEGIN;
PRINT 'Executing DBCC INDEXDEFRAG (0, ' + RTRIM(@tablename) + ',' + RTRIM(@indexid) + ') - fragmentation currently '
+ RTRIM(CONVERT(varchar(15),@frag)) + '%';
SELECT @execstr = 'DBCC INDEXDEFRAG (0, ' + RTRIM(@objectid) + ',' + RTRIM(@indexid) + ')';
EXEC (@execstr);

FETCH NEXT
FROM indexes
INTO @tablename, @objectid, @indexid, @frag;
END;

-- Close and deallocate the cursor.
CLOSE indexes;
DEALLOCATE indexes;

-- Delete the temporary table.
DROP TABLE #fraglist;
GO



Esto va a tener una salida similar a esta:


Executing DBCC INDEXDEFRAG (0, Entity,1) - fragmentation currently 97%
Pages Scanned Pages Moved Pages Removed
-------------------- -------------------- --------------------
28 22 3

DBCC execution completed. If DBCC printed error messages, contact your system administrator.
Executing DBCC INDEXDEFRAG (0, Entity,2) - fragmentation currently 97%
Pages Scanned Pages Moved Pages Removed
-------------------- -------------------- --------------------
32 15 10

DBCC execution completed. If DBCC printed error messages, contact your system administrator.
Executing DBCC INDEXDEFRAG (0, EntityVersion,1) - fragmentation currently 59%
Pages Scanned Pages Moved Pages Removed
-------------------- -------------------- --------------------
262 243 15

DBCC execution completed. If DBCC printed error messages, contact your system administrator.



que incluye las paginas leidas, movidas y borradas (Pages Scanned, moved, removed), por cada índice defragmentado.

Comentarios

  1. Hola Enrique, qué beneficios trae hacerlo? tuviste alguno visible?
    Saludos, Armin

    ResponderBorrar
  2. Armin:
    Defragmentar los indices disminuye el tamaño de los mismos y tambien hace que las consultas tengan que hacer menos lecturas a disco para devolver los registros.

    Cuando un indice esta muy fragmentado, generalmente realiza mas lecturas para devolver los mismos registros, que si el indice esta sin fragmentacion.

    Tambien reduce un poco el tamaño que ocupa el indice, pues libera algunas paginas, que pueden recuperarse haciendo un shrink de la base o de los archivos de la misma.

    En KB chicas no se va a notar mucho, pero en KB grandes y con muchas revisiones en los objetos, o con muchas versiones (modelos) la diferencia puede ser mas notoria.

    Se puede ver esto, ejecutando el profiler sobre la base de datos y revisar la cantidad de lecturas de las sentencias.

    Toda base de datos, necesita mantenimiento.

    ResponderBorrar
  3. Enrique,

    muy bueno!

    Pero dejame anotar unas pequeñas modificaciones que tuve q hacer cuando el "owner" de las tablas no es el "dbo":

    agregar en las declaraciones:
    DECLARE @schemaname varchar(128);

    cambiar
    DECLARE tables CURSOR FOR
    SELECT TABLE_NAME
    FROM INFORMATION_SCHEMA.TABLES
    WHERE TABLE_TYPE = 'BASE TABLE';

    por
    DECLARE tables CURSOR FOR
    SELECT TABLE_SCHEMA,TABLE_NAME
    FROM INFORMATION_SCHEMA.TABLES
    WHERE TABLE_TYPE = 'BASE TABLE';

    y por final, cambiar
    EXEC ('DBCC SHOWCONTIG (''' + @tablename + ''')

    por

    EXEC ('DBCC SHOWCONTIG (''' + @schemaname+'.'+@tablename + ''')


    y todo anda bien.

    Gracias por el script. Funciona barbaro.

    ResponderBorrar
  4. Sandrix:
    Gracias por las mejoras.

    Para SQLServer 2010, estoy usando otro que es mas rapido. Luego con mas tiempo lo publico.

    ResponderBorrar
  5. Bueno, muy interesante la parte de los índices. Pero persiste una duda, ¿Cómo se defragmentan las tablas?
    Si me puedes dar una pequeña ayuda, te lo agradecería enormemente.
    Gracias.

    ResponderBorrar
    Respuestas
    1. Los datos en sql server se almacenan en indices especiales, (no en el caso general , pero si como genexus crea los tablas). Por lo tanto al de fragmentar los indices, también se de fragmentan las tablas y sus datos.

      Borrar

Publicar un comentario

1) Lee el post
2) Poné tu opinión sobre el mismo.
Todos los comentarios serán leidos y la mayoría son publicados.

Entradas más populares de este blog

La nefasta influencia del golero de Cacho Bochinche en el fútbol uruguayo

Aplicación monolítica o distribuida?

Funcionalidades de GeneXus que vale la pena conocer: DATE Constants.