sábado, 20 de diciembre de 2014

Cambiar el Nombre de Una Base de Datos

Amigos,

     Me han preguntado por mail si es posible cambiar el nombre de una base de datos... La persona que me hizo llegar su correo se la notaba preocupada ya que había creado una base y luego había avanzado en el montado de estructuras, users, permisos etc.

     Luego de dos dias de trabajo, a este desarrollador de Guatemala, le llegó la orden de cambiar el nombre de la base puesto que el Project Leader así lo solicitaba.

     El intentó hacerlo pero fracasó, ya que no no siguió los siguientes pasos... .

     Se los dejo, es algo muy sencillo y efectivo...

         
 -- Se setea la base de datos en "Single User"
Alter Database A
Set Single_User with rollback immediate

-- Modifico el Nombre de la Base de Datos --
ALTER DATABASE A
Modify Name = B;
GO

-- Vuelvo la Base de Datos ya renombrada a Multi User --
Alter Database B
Set Multi_User
     

** Por último, sólo es posible cambiar el nombre de las BD de usuarios no de las BD del sistema.

Eso es todo amigos, saludos para todos.

miércoles, 10 de diciembre de 2014

Pregunta: Cómo identifico cual dts package está siendo llamado por el job?

PREGUNTA:


Bruno xxxx
 xxxxx@hotmail.com





Buenas tardes Gustavo.

Te saluda Bruno de Lima-Perú. Estuve buscando la solución a un problema que tengo en sql server y me encontré con tu blog, déjame felicitarte por el trabajo que realizas, he encontrado mucha información.

Te comento que no soy DBA, pero tengo nociones. Estoy realizando un inventario de todos los Jobs y dts de la base de datos sql server 2000.

Cuando estuve inventariando los dts me encontré con esta sorpresa.

He encontrado en la línea de ejecución lo sgte:


DTSRun /~Z0xAABAD4ECCF4B2A08AC5ACF14850EF2865FE933FCD50929A5FB0B21F1200CE14D2A492C5F73D719EAFBCA077C0AC0079B52FC5B1B26771622389205196AA5D334DF6F163A895DFB9F6B66507626FF70285419B49123265B8368DFB9F4777D5A2B4F00238BCB7D2B75A960DC14C00BFC1464C23A7F69114D48108EAD49F684055F26066F7E82A236ABF58F9202EC071FA8F60193

Aquí esta mi duda, no se como se llama el dts.
Que puedo hacer para saber el nombre del dts y de sus parámetros?
Espero me puedas ayudar.
Muchas gracias por todo y que sigas ayudando !!

Respuesta.

Estimado Bruno, muchas gracias por tus conceptos, sigue los siguientes pasos:

1) Copia la línea DTSRUN
2) Abre una ventana de Windows Command
3) Pega la línea DTSRUN dentro de la ventana
4) Al final de la línea agrega (textual) /!X/!C = copy results onto Windows Clipboard
5) Corre el comando
6) Abre el notepad
7) Cliquea "EDIT PASTE", esto va a pegar el comando actual dentro del Notepad
 y te mostrará a ti el nombre del Package.

Suerte y quedo a tu disposición

Gustavo Herrera.

Pregunta "En la empresa donde trabajo utilizan sql server standard edition y no tiene disponible la opción de particionar, que puedo hacer si tengo una tabla de 10 millones de registros?"



PREGUNTA

Alejandro xxxxxxx @yahoo.com




Cordial saludo
Buenos días , señor Gustavo
Mi nombre es Fabio Hernández , trabajo en el área de desarrollo .net y bases de datos sql server , vi un blog suyo muy interesante y habla del tema de particionamiento de tablas SQL SERVER PARA TODOS Gustavo Ricardo Herrera : PARTICIONAR TABLAS EN 5 PASOSEn la empresa donde trabajo utilizan sql server standard edition y no tiene disponible la opcion de particionar, que puedo hacer si tengo una tabla de 10 millones de registros , en donde hay información histórica desde el año 2000 hasta el 2014, normalmente la información consultada es del 2012-2014 , pero en la tabla esta todo el historico, como no puedo particionar por la version del sql server que otra opcion podria hacer
Muchas gracias .
Att
xxxxxxx


CONTESTACION

Que tal Alejandro, saludos desde BsAs.

Perdón por la demora en contestarte, estoy muy atareado por estos dias.

Lo que te ocurre a Ti le ocurre a mucha gente... Van mis consideraciones...

-  Se te ha abierto una oportunidad de solicitarles a los dueños de la compañía para la cual trabajas el upgrade hacia una versión más profesional de Sql Server.  Has pie en la ecuación costo/beneficio y trata pues de explicarles - en el lenguaje más sencillo posible - uno de los problemas a los que se enfrenta la compañía (perfromance pobre de sus bases de datos), por no tener la versión adecuada de Sql Server.

- Una tabla de 10 millones de registros es, a priori, una tabla que no tendría que particionarse, al menos por la cantidad de registro que refieres. Recuerda siempre que el mantenimiento de una partición es una tarea más a futuro...

- Entiendo que tu problema pasa por otro lado...., veamos...

   Pienso que deberías hacer pie en algunos de los siguientes items antes de pensar en particionar.

   -  Determinación de las queries que más tiempo tardan en resolverse (hay un script en mi blog para ello)

   -  Estudio de los planes de ejecución de dichas queries. Apuesto hacia falta de un indexado apropiado o de una lógica "pobre" en las queries a las que te hago referencia.
    
   Por otra parte, desconozco si dispones de, al menos 3 discos físicos para poder distribuir los archivos de datos, log e índices en distintos discos y aprovechar de ese modo la lecto escritura paralela del sql server.

   Una última solución puede ser, yo no te la aconsejo, el crear una base de datos por año y luego simplemente joinear las consultas.

   Entiendo que habiendo revisado los anteriores puntos (planes de ejecución, indexado y lógica de las queries),  encontrarás la solución, sin precisar hacer esto último. 

   Suerte y quedo atento ante cualquier inquietud.

    Saludos desde Buenos Aires, Gustavo Herrera.   

miércoles, 6 de agosto de 2014

TRIGGERS - (DML - DDL)

Amigos, 

    Quiero acercarles un artículo que he preparado para este blog relacionado con los triggers.     Tipos, utilidad, consideraciones generales....

     Todo al estilo de este blog, sencillo y con ejemplos.

     Espero que les sea útil, saludos.




DML Triggers

·         Son procedimientos almacenados  que se ejecutan automáticamente ante un evento DML  (Update – Delete – Insert) que afecta  una tabla o vista.

·         Se los puede utilizar para, una vez desencadenados:
-          Forzar reglas de negocio
-          Mantener la integridad de datos
-          Querear otras tablas
-          Ejecutar complejas instrucciones SQL

·         La integridad debiera ser forzada al nivel más bajo por índices que formen parte de un Primary Key o Foreing Key contraints -
·         Los CHECK Constraints son otra alternativa
·         Para asegurar la Integridad Referencial nada mejor que los Foreing Key
·         Los DML TRIGGERS son especialmente utilizados cuando,con el simple uso de un constraint, no se cubren  las necesidades de una aplicación
     
·         Consideraciones Generales y Beneficios:

·        *   No se pueden invocar por si mismos, se disparan automáticamente
·        *   No reciben ni retornan parámetros
·        *    A diferencia de los constraint “check” pueden hacer referencia a otras tablas (por ejemplo se puede controlar una inserción en una tabla de ventas si y solo si el valor de un campo stock de una tabla artículos sea mayor a x cantidad)
·        *   Se pueden crear más de un trigger para un mismo evento en una tabla, con lo cual se pueden controlar múltiples alternativas sobre la misma tabla.
·       *   Permiten evaluar el estado de una tabla antes y después de una modificación y tomar acciones acorde a la evaluación
·         *   Permiten customizar mensajes de error, algo que los constraints en general no permiten.

·         Syntaxis:
CREATE TRIGGER <Nombre del Trigger>
ON <Nombre de la Tabla>
AFTER <INSERT,DELETE,UPDATE>
      AS
BEGIN
SET NOCOUNT ON;
-- Inserta aquí las instrucciones
END
·         Consideraciones Adicionales:

-          Los triggers DML utilizan dos tablas especiales denominadas InsertedDeleted.
-          Son tablas creadas automáticamente por el SQL con la misma estructura que la tabla sobre la cual está definido el trigger
-          La tabla Inserted solo tiene datos en operaciones de Insert y Update
-          La tabla Deleted  sólo tiene datos en operaciones de Delete y Update
-          En caso de un update las tablas Inserted y Deleted tienen data al mismo tiempo.
-          No se pueden modificar los datos de estas tablas

·         Ejemplos:

1)      Se graba un histórico de stock cada vez que se modifica un artículo de la tabla “articulos”
      -----------------------------------------------------------------
      --  TRIGGER DML                                                                            
      --  Detalle: este trigger genera un histórico de stock cada vez 
          que se modifica la existencia de un artículo --
      -----------------------------------------------------------------
      CREATE TRIGGER TR_ARTICULOS
      ON ARTICULOS
      AFTER UPDATE
      AS
        BEGIN
         INSERT INTO HCO_STOCK
         (IDARTICULO, STOCK, FECHA)
         SELECT IDARTICULO, STOCK, getdate()
         FROM INSERTED
        END

       --- Con este evento UPDATE se desencadena el Trigger

      UPDATE ARTICULOS
      SET STOCK = STOCK + 10
      WHERE IDARTICULO = 1

2)       Podemos hacer que el trigger del ejemplo 1 se desencadene sólo si una columna es afectada
      CREATE TRIGGER TR_ARTICULOS
      ON ARTICULOS
      AFTER UPDATE
      AS
        BEGIN
           IF UPDATE (STOCK)    -- sólo si actualiza STOCK
            BEGIN
             INSERT INTO HCO_STOCK
             (IDARTICULO, STOCK, FECHA)
             SELECT IDARTICULO, STOCK, getdate()
             FROM INSERTED
            END
END
3)      Podemos hacer que el trigger  deshaga toda la operación incluyendo un ROLLBACK
      CREATE TRIGGER TR_ARTICULOS
      ON ARTICULOS
      AFTER UPDATE
      AS
        BEGIN
             INSERT INTO HCO_ARTICULOS
             (IDARTICULO, STOCK, FECHA)
             SELECT IDARTOCULO, STOCK, getdate()
             FROM INSERTED
               
             ROLLBACK
END

4)      Podemos DESACTIVAR/ACTIVAR  un Trigger o Todos lo Triggers de la tabla
      ----------------------------------------------------------
      -- Desactivar y Activar Todos los Triggers de una Tabla --
      ---------------------------------------------------------

      -- Desactiva todos los trigger de la tabla ARTICULOS
      ALTER TABLE ARTICULOS DISABLE TRIGGER ALL
      GO
      -- Activa todos los trigger de la tabla ARTICULOS
      ALTER TABLE ARTICULOS ENABLE TRIGGER ALL

      ----------------------------------------------------
      -- Desactivar y Activar Un Trigger en Particular --
      ---------------------------------------------------

      -- Desactiva el trigger TR_STOCK
      DISABLE TRIGGER TR_STOCK ON ARTICULOS
      GO
      -- Activa el trigger TR_STOCK
      ENABLE TRIGGER TR_STOCK ON ARTICULOS
      GO  







DDL Triggers

·         Son triggers especiales que se crean a nivel de base de datos y que disparan en respuesta a eventos DML  (Update – Delete – Insert)

·         Suelen ser utilizados para ejecutar tareas administrativas en una base de datos auditando y regulando cierta clase de eventos.


·         Syntaxis:
CREATE TRIGGER <Nombre del Trigger>
ON DATABASE
FOR <DROP TABLE, ALTER TABLE>
AS
BEGIN
   SET NOCOUNT ON;
   -- Inserta aquí las instrucciones
END

      
·         Ejemplos:

1)      El siguiente trigger impide que sentencias DROP TABLE y ALTER TABLE a nivel de Base de Datos
               CREATE TRIGGER TR_Seguridad
       ON DATABASE FOR DROP_TABLE, ALTER_TABLE
       AS
       BEGIN
         RAISERROR ('No está permitido borrar ni modificar tablas !' , 16, 1)
         ROLLBACK TRANSACTION

       END

miércoles, 30 de abril de 2014

MANTENIMIENTO DE ESTADISTICAS (update statistics) - Tarea Impostergable Para Mejorar la Performance de Nuestras Queries

    Y bien amigos, otra vez tengo el placer de ponerme en contacto con Uds...

    En esta oportunidad quiero hablarles de un tema fundamental para el mejor funcionamiento de nuestro entorno... ESTADISTICAS...

    Me atrevería a afirmar que LAS ESTADISCTAS son tan importantes como los índices a la hora de darle a nuestro motor de base de datos las mejores herramientas para que elija el plan de ejecución óptimo, ese que permita que nuestros tiempos de respuesta sean la envidia de otros quienes no leen este post ;)

    Encontrarán en este artículo toda la teoría y los scripts necesarios para que sus estadísticas estén al % 100 de sus posibilidades

    Sin más, "go down to business"... cualquier duda estoy para responder sus preguntas.

 1)      QUE SON LAS ESTADISTICAS?

      Son objetos utilizados por el Optimizador de Consultas del Sql Server para entender la cantidad y distribución de la data dentro una o varias columnas y de esa forma tomar la mejor elección dentro del mismo.

      Hay dos tipos de estadísticas:

      Index Statics: que son creadas automáticamente cuando se crea cualquier tipo de idx (con el mismo nombre que el índice)

     Column Statics: son creadas manualmente por el DBA usando el comando “CREATE STATICS” o automáticamente por el Sql Server cuando la opción “Auto Create Statics” está seteada en “True”.-



   2)       MANTENIMIENTO DE ESTADISTICAS

       Cuando la data en una BD cambia las estadísticas  pueden quedar desactualizadas y hacer que los planes de ejecución no tomen las mejores decisiones.

       Si hay una diferencia considerable en el “Actual Number of Rows” y el “Estimated Number of Rows” cuando examinamos un plan de ejecución, seguramente debemos actualizar estadísticas.


Mantener “Auto Create Statics” enabled:  esta opción le permite al SQL crear automáticamente estadísticas cuando para columnas no indexadas  no existen estadísticas previamente creadas y el Sql las necesita para un Join o un Where.  La estadísticas creadas automáticamente por el SQL Server comienzan con “_WA_” en el nombre

      Mantener “Auto Update Statics” enabled:  esta opción le permite al 
       SQL  actualizar las estadísticas cuando considera que están desactualizadas.
     
      Hay tres condiciones que pueden desencadenar la actualización automática de 
      estadísticas de parte del Sql Server:

       --  Cuando la tabla no tiene registros y al menos suma uno o más
       --  Cuando la tabla tiene menos de 500 registros y los mismos se incrementan en 
             500 o más desde el último udpate.
       --  Cuando la tabla tiene más de 500 registros y su valor se incrementa en un % 20
             de su tamaño.


               
            3)     PENSAR EN UNA RUTINA DE MANTEMIENTO DE ESTADISTICAS

             El preparar un job que haga un update de estadísticas fuera de las horas pico puede 
         ayudar al Sql a que reduzca la necesidad de actualizar estadísticas durante las horas pico.

              La frecuencia en la que debe correr nuestro plan estará sujeta a nuestro entorno. 
              Si  tenemos un entorno con actualizaciones frecuentes nuestras estadísticas van a
          quedar desactualizadas con mayor frecuencia.

              También debemos tener en cuenta que  el actualizar estadísticas fuerza a las queries 
           a recompilar los planes de ejecución, y eso tiene un costo.

         Dentro de la rutina de mantenimiento de estadísticas no debemos, al menos una vez 
     al mes, el borrar las estadísticas “innecesarias” (luego veremos en detalle este concepto)
      
       

      4)      SCRIPTS DE MANTENIMIENTO DE ESTADISTICAS

Consta de dos pasos a saber:

Paso 1:  Borrado de Estadísticas Innecesarias y/o Redundantes

El tener estadísticas  por demás genera una mayor sobrecarga en el sql server a la hora de mantener las mismas.

Cuando hablamos de “estadísticas innecesarias y/o redundantes” podemos dividir las mismas en dos casos puntuales a saber:

-          Estadísticas automáticas creadas por el SQL Server para resolver alguna consulta puntual que no han tenido actualización desde su creación, lo cual nos habla de estadísticas que ya no se utilizan.

-          Estadísticas de Columnas que ya están cubiertas por Estadísticas de Indices, siempre que compartan la misma columna leader


Script “Erase_Unnecesary_Statictis”


 GO
=========================================================
--Author:  Gustavo Herrera                                               
-- Create date: Abril 2014                                                
-- Description:   Mantenimiento de Estadístcas - Borrado de Estadísticas Innecesarias y/o Redundantes  --
=========================================================

ALTER PROCEDURE [dbo].[DBA_Erase_Unnecesary_Statictis]
AS
BEGIN

SET NOCOUNT ON;
               
 ---------------------------------- ---------------------------------------------------------------------
  -- 1) BORRADO ESTADISTICAS CREADAS POR SQL SERVER Y NUNCA UPDETEADAS 
  -------------------------------------------------------------------------------------------------------

  -- Declaración Variables Generales --
  Declare
  @Table varchar(30),
  @Static varchar(30),
  @SQL nvarchar(MAX),
  @VSentenciaBorrado varchar(300)

    -- Declaro cursor --
    Declare Cur_Delete_1 Cursor For

     -- Guardo en el Cursor --
     SELECT
    OBJECT_SCHEMA_NAME(st.object_id) + '.' + OBJECT_NAME(st.object_id) as 'Table',
     st.name as 'Stat'
     FROM sys.stats st with (nolock)
     --
     Join sys.stats_columns AS scol (NOLOCK)
     ON st.stats_id = scol.stats_id AND
      st.object_id = scol.object_id
      --  
     WHERE
     STATS_DATE(st.object_id, st.stats_id) is  null AND -- alguna vez actualizadas
     OBJECT_SCHEMA_NAME(st.object_id) + '.' + OBJECT_NAME(st.object_id)not like'sys%' and
     st.name LIKE '_WA%'
     --
     ORDER BY
     OBJECT_SCHEMA_NAME(st.object_id) + '.' + OBJECT_NAME(st.object_id)

      -- Abro el Cursor -- 
      Open Cur_Delete_1

      -- Lo recorro --
      Fetch Next From Cur_Delete_1
       into
              @Table,
              @Static
                  --
               While @@FETCH_STATUS = 0
                Begin
                        SET @SQL = 'DROP STATISTICS ' + @Table + '.' + @STATIC
                        EXEC sp_executesql @SQL
                         --Paso al siguiente valor del vector
                        Fetch Next From Cur_Delete_1
                        into
                        @Table,
                        @Static
                  End
               
        -- Cierro cursor --
        Close Cur_Delete_1

        -- Saco cursor de memoria --
        Deallocate Cur_Delete_1


  ----------------------------------------------------------------
  -- 2) BORRADO DE ESTADISTICAS REDUNDANTES --
 ----------------------------------------------------------------

 -- A) Guarda en una tabla temporal las Etadísticas de Columna Autocreadas por el sql  --
    
 SELECT 
  a.object_id ,
  a.stats_id ,
  a. name ,
  b.column_id,
  a.auto_created
 INTO #autostats
 FROM sys.stats as a with (nolock)
 ---
 left JOIN sys.stats_columns as b
 ON  a.object_id = b.object_id
 AND a.stats_id = b.stats_id
  --
 WHERE
 a.auto_created = 1 AND -- creada por el sql server
 b.stats_column_id = 1

 -- Declaro cursor --
 Declare Cur_Delete_2 Cursor For

 -- Guardo en el Cursor --

-- B) Comparando con la tabla ##autostats se determinan cuales estadísticas se superponen y deben ser borradas --

SELECT 
'DROP STATISTICS [' + OBJECT_SCHEMA_NAME(sys.stats.object_id)+ '].[' + OBJECT_NAME(sys.stats.object_id) + '].['+ #autostats.name + ']' as sentence
FROM    sys.stats with (nolock)
 ----
 INNER JOIN sys.stats_columns ON
 sys.stats.object_id = sys.stats_columns.object_id and  -- pertencen al mismo objeto
 sys.stats.stats_id = sys.stats_columns.stats_id -- el mismo id de estadistica
  ---
 INNER JOIN #autostats ON
 sys.stats_columns.object_id = #autostats.object_id and  -- que sea el mismo objeto
 sys.stats_columns.column_id = #autostats.column_id      -- que se la misma columna  
 ----
INNER JOIN sys.columns ON
sys.stats.object_id = sys.columns.object_id and        --  que sea la misma columna 
sys.stats_columns.column_id = sys.columns.column_id
---
WHERE
sys.stats.auto_created = 0 AND  -- que sea autocreado
sys.stats_columns.stats_column_id = 1 AND
sys.stats_columns.stats_id <> #autostats.stats_id AND -- compara id de estadística
OBJECTPROPERTY(sys.stats.object_id, 'IsMsShipped') = 0

-- Abro el Cursor -- 
Open Cur_Delete_2

-- Lo recorro --
Fetch Next From Cur_Delete_2
into @VSentenciaBorrado
While @@FETCH_STATUS = 0
    Begin
         SET @SQL = @vsentenciaborrado
          --   print @vsentenciaborrado
          EXEC sp_executesql @SQL
            --Paso al siguiente valor del vector
           Fetch Next From Cur_Delete_2
            into
             @VSentenciaBorrado
      End
                      
  -- Cierro vector --
  Close Cur_Delete_2

 -- Lo saco de memoria --
 Deallocate Cur_Delete_2

END


Paso 2:  UPDATE DE LAS ESTADISTICAS EXISTENTES

Como hemos explicado en el punto 3) , es una tarea de suma importancia portancia mantener nuestras estadísticas actualizadas. Diría que es tan importante como mantener nuestro índices.}

Para ello hay dos formas que explico debajo.

Mi elección claramente es inclinarse por la más laboriosa pero efectiva de estas dos formas. Les dejo un script listo para su utlización al final de esta breve explicación

3.1) SP_UPDATESTATSel cual regenera todas las estadísticas de una base de datos en base a los cambios registrados en la columna rowmodctr de la vista sys.sysindexes.

Ventaja: Es fácil de implementar
Desventajas:  Es poco preciso. Termina regenerando estadísticas innecesariamente cuando, por ejemplo, una tabla tuvo un insert/delete o update de un solo registro (algo que afecta la columna rowmodctr de la vista sys.sysindexes).

Es poco customizable, siempre regenera estadísticas tomando el mismo algoritmo el cual no es modificable y en ocasiones no representa un muestreo válido de la tabla.
  e.g:
EXEC sp_updatestats

3.2)  UPDATE STATISCS:  para hacer un update de las estadísticas de una tabla/de un índice específico/de una campo de una tabla en particular.

Ventaja:  Es mucho más cutomizable y efectivo que el sp_updatestats.
Desventaja: Es de implementación algo más compleja que el sp_updatestats
La mayor efectividad de este tipo de update está basada en la posibilidad de elegir el % de muestreo que el motor de base de datos tendrá en consideración a la hora de actualizar las estadísticas.

UPDATE STATICS Table Name (Stats Name) WITH FULLSCAN à insume más tiempo y recursos pero asegura estadísticas exactas. Toma muestreo el % 100 de la tabla
UPDATE STATICS Table Name (Stats Name) WITH SAMPLE 50 PERCENT à al usar solo el %50 como muestreo insume menos recursos y tiempos pero las estadísticas no son tan exactas. Toma el % de muestreo que le indiquemos.
e.g:
 -- Update all statistics on a table
 UPDATE STATISTICS Sales.SalesOrderDetail
 -- Update a specific index on a table
 UPDATE STATISTICS Sales.SalesOrderDetail IX_SalesOrderDetail
 -- Update one column on a table specifying sample size
UPDATE STATISTICS Production.Product(Products) WITH SAMPLE 50 
PERCENT


Script “Erase_Unnecesary_Statictis”



USE [xxxx]

GO
SET QUOTED_IDENTIFIER ON
GO

==========================================================
-- Author:        Gustavo Herrera                                                                                                               --
-- Create date: 28/04/2014                                                                                                                      --
-- Description:   Mantenimiento de Estadístcas - Actualización Semanal de Estadísticas  
-- =========================================================

CREATE PROCEDURE [dbo].[DBA_Update_Statictis]
AS
BEGIN


SET NOCOUNT ON;
-- Declaración de Variables --
Declare
@Table varchar(30),
@Static varchar(30),
@SQL nvarchar(MAX),
@SampleSize varchar(20)
 Set @SampleSize = ' WITH FULLSCAN'

 -- Declaro cursor --
 Declare Cur_Stats Cursor For

 -- Guardo en el Cursor --
 SELECT
 distinct
 OBJECT_SCHEMA_NAME(st.object_id) + '.' + OBJECT_NAME(st.object_id) as 'Table'
 FROM sys.stats st WITH (nolock)
  --
 Join sys.stats_columns AS scol (NOLOCK)
 ON st.stats_id = scol.stats_id AND
  st.object_id = scol.object_id  
  WHERE
  STATS_DATE(st.object_id, st.stats_id) is not null and -- que alguna vez se hayan actualizado
  DATEDIFF(DAY, STATS_DATE(st.object_id, st.stats_id), GETDATE()) > 6 and --ult upd > 6 d
  OBJECT_SCHEMA_NAME(st.object_id) + '.' + OBJECT_NAME(st.object_id)not like'sys%' -- que no   --sean objetos del sistema
  ORDER BY
  OBJECT_SCHEMA_NAME(st.object_id) + '.' + OBJECT_NAME(st.object_id)


   -- Abro el Cursor -- 
  Open Cur_Stats

   -- Lo recorro --
   Fetch Next From Cur_Stats
        into
        @Table
    --
       While @@FETCH_STATUS = 0
        Begin
             SET @SQL = N'UPDATE STATISTICS ' + @Table +@SampleSize
             EXEC sp_executesql @SQL
                   
               --Paso al siguiente valor del vector
              Fetch Next From Cur_Stats
               into
                  @Table
        End
         
    -- Cierro vector --
    Close Cur_Stats

      -- Lo saco de memoria --
     Deallocate Cur_Stats
END

GO


            5)   CONSIDERACIONES FINALES  SOBRE ESTADISTICAS

5.1)  El INDEX REBUILD hace un update de las estadísticas con Full Scan. Por lo tantono se recomienda hacer un mantenimiento de estadísticas luego de un mantenimiento de idx para no duplicar el trabajo.

5.2)  EL INDEX REORGANIZE hace un update de estadísticas pero sin FULL SCAN.

5.3)  No confiar en el Auto Update Statics, puesto que, como hemos visto, se desencadena luego de que la tabla ha tendido modificaciones en un % 20 de sus registros. Si la tabla es muy grande… pocas chances de que suceda.

5.4)  Es muy importante elegir criteriosamente % del muestreo que el Sql Server va a tomar para hacer la recreación de las estadísticas. En tablas de un tb por ejemplo es aconsejable que sea un FULL SCAN, de lo contrario, las  estadísticas serán inexactas y el Sql Server no tomará las decisiones correctas

5.5)  Recordar que TODOS LOS PLANES DE EJECUCION QUE UTILIZAN ESTADISTICAS SERAN REGENERADOS CUANDO DICHAS ESTADISTICAS SEAN ACTUALIZADAS.

5.6)  A priori, el actualizar las estadísticas una vez por semana en horas de mínima concurrencia es una buena medida para entornos con moderada a alta actualización de sus registros.