martes, 15 de noviembre de 2016

Property Owner is not Available for Database '[ ]'. This property may not exist for this object, or may not be retrivable due to insufficient acces rights (Microsoft.SqlServer.Smo) // SOLUCION AL PROBLEMA

Buen dia amigos,

   Hoy quiero contestar una pregunta de don Armando Gonzalez del Rio quien nos escribe desde Monterrey en el querido país Azteca.

    Don Armando refiere que trabaja para una cia donde fueron despedidos empleados del Depto de Sistemas, alguno de los cuales cumplían funciones de DBA.
 
    Concreteamente el problema que nos refiere es "cuando intento clickear sobre una base de datos y obtener sus propiedad me encuentro imposibilitado de hacerlo y me aprece este cartel:"


Solución:

 Don Armando ud no puede acceder a las propiedades de las bases de datos puesto que el owner de las mismas a quedado ligado a los empleados de la empresa que han sido desafectados de la misma.

  Tiene pues que correr un comando asignando la base de datos a un login, preferentemente de domino, que esté asignado a un empleado del payroll actual de la Cia.

  Cómo se hace? Pues de la siguiente forma, utilizando el sp sp_changedbowner.

  use [base de datos]

exec sp_changedbowner 'gherrera';


En el ejemplo precedente se asigna un nuevo owner al login "gherrera".

Es todo amigos, nos vemos proximamente.

Saludos desde Argentina.



   




jueves, 27 de octubre de 2016

Problemas al Renombrar Una Base de Datos

Amigos, 

   Hoy es un dia de respuesta a preguntas. Tabaré Montero de Las Cañas Uy me refiere un problema a la hora de renombrar las bases de datos... 
   Tbaré me comenta que lo hace a través de la consola, "parándose sobre la base de datos", "clickeando" con botón derecho y utilizando la opción "rename". El resultado... obtiene siempre un mensaje de error.
   Pablo, para evitar errores a la hora de renombrar una base de datos no hay otra forma que hacerlo en modo monousuario y con sentencias t-sql , no con la consola, veamos:

-----------------------------------------------
 -- Autor GH para
 -- Detalle: Renombrar Una Base de Datos
 -----------------------------------------------

-- 1 Seteo la Base de Datos a Single User

Alter Database Repuestos
Set Single_User with Rollback Immediate

2-- Renombro la Base de Datos

ALTER DATABASE Respuestos
Modify Name = RespuestosFord ; 

-- 3 Seteo la Base de Datos a Multi User
Alter Database RepuestosFord

Set Multi_User

 
Amigo, un saludo grande a la gente de Fray Bentos, Las Cañas. A su disposición



Scriptear Todos los Indices de Una Base de Datos (con un solo script)

Amigos,

   Cuantas veces nos encontramos ante una migración con la necesidad de contar con la ayuda de un script que nos permita scriptear todos los Indices de todas las tablas de una base de datos?
   Estoy seguro que muchas veces se han efrentado a esta situación y, por cierto, no parece la situación ideal "pararse" sobre cada tabla y con el botón derecho scriptear cada uno de los idx...
   Les dejo entonces un script que hace esto por ustedes, solo lo ejeutan y el resultado en formato texto será el script con el cual podrán regenerar uno a uno todos los índices de todas las tablas de una base de datos.
   Aprovecho para saludar al amigo Agapito Buenaventura quien me ha escrito preguntando por este tema desde la querida Bolivia.

  ---------------------------------------------------------------------------
-- Autor Gustavo Herrera                                                
-- Detalle: Este código scriptea todos los indices correspondientes a una BD 
-----------------------------------------------------------------------------

DECLARE cIX CURSOR FOR
   SELECT
   OBJECT_NAME(SI.Object_ID),
   SI.Object_ID,
   SI.Name,
   SI.Index_ID,
   F.NAME
   FROM Sys.Indexes SI
   LEFT JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS TC
   ON
    SI.Name = TC.CONSTRAINT_NAME AND
    OBJECT_NAME(SI.Object_ID) = TC.TABLE_NAME
   LEFT JOIN sys.filegroups f -- para saber el filegroup
   ON SI.data_space_id = f.data_space_id
   WHERE --TC.CONSTRAINT_NAME IS NULL --AND
         OBJECTPROPERTY(SI.Object_ID, 'IsUserTable') = 1
          ORDER BY OBJECT_NAME(SI.Object_ID), SI.Index_ID

   DECLARE
   @IxTable SYSNAME,
   @IxTableID INT,
   @IxName SYSNAME,
   @IxID INT,
   @PKSQL varchar (50),
   @FILEGROUP VARCHAR (50)

   -- Loopea a través de todos los idx
   OPEN cIX
   FETCH NEXT FROM cIX INTO
   @IxTable, @IxTableID, @IxName, @IxID, @FILEGROUP
  
   WHILE (@@FETCH_STATUS = 0)
   BEGIN
       DECLARE @IXSQL NVARCHAR(4000) SET @PKSQL = ''
       SET @IXSQL = 'CREATE '

       -- Chequea si el indice es unique
       IF (INDEXPROPERTY(@IxTableID, @IxName, 'IsUnique') = 1)
        SET @IXSQL = @IXSQL + 'UNIQUE '
       -- Chequea si el idx es clustered
       IF (INDEXPROPERTY(@IxTableID, @IxName, 'IsClustered') = 1)
        SET @IXSQL = @IXSQL + 'CLUSTERED '
        SET @IXSQL = @IXSQL + 'INDEX ' + @IxName + ' ON ' + @IxTable + '('

         -- Obtiene todas las columnas que contienen índices
         DECLARE cIxColumn CURSOR FOR
              SELECT SC.Name
              FROM Sys.Index_Columns IC
                   JOIN Sys.Columns SC ON IC.Object_ID = SC.Object_ID AND IC.Column_ID = SC.Column_ID
              WHERE IC.Object_ID = @IxTableID AND Index_ID = @IxID
              ORDER BY IC.Index_Column_ID

            DECLARE
            @IxColumn SYSNAME,
            @IxFirstColumn BIT
            SET @IxFirstColumn = 1

            -- Loopea a través de todas las columnas que forman un idx y les agrega un CREATE
            OPEN cIxColumn
            FETCH NEXT FROM cIxColumn INTO @IxColumn
            WHILE (@@FETCH_STATUS = 0)
            BEGIN
                IF (@IxFirstColumn = 1)
                    SET @IxFirstColumn = 0
                ELSE
                    SET @IXSQL = @IXSQL + ', '
             SET @IXSQL = @IXSQL + @IxColumn

                  FETCH NEXT FROM cIxColumn INTO @IxColumn
            END
            CLOSE cIxColumn
            DEALLOCATE cIxColumn

            SET @IXSQL = @IXSQL + ') '+'ON '+@FILEGROUP
            
            
           
          -- Imprime CREATE statement para los índices
   PRINT @IXSQL

   FETCH NEXT FROM cIX INTO @IxTable, @IxTableID, @IxName, @IxID, @FILEGROUP
END

CLOSE cIX
DEALLOCATE cIX
 

Listar TABLAS IDENTITY de una Base de Datos

Buenas tardes amigos.
Estoy en el dia de hoy respondiendo una pregunta hecha por don José Bermudez de la bella zona de Cartagena Colombia.
Don José me pregunta si es posible identificar con un script aquellas tablas que tienen una columna autoincremental "identity".

Pues claro que si, le dejo pues el script y mis saludos a la tierra del buen café y los hermosos paisajes.

 --------------------------------------------------------------------------
 -- Autor GH para SQL SERVER PARA TODOS                                                               
 -- Detalle: Lista todas las tablas que tengan columna identity de una BD --
 ---------------------------------------------------------------------------

 SELECT
 TABLE_NAME,
 COLUMN_NAME
 FROM INFORMATION_SCHEMA.COLUMNS
 WHERE
 TABLE_SCHEMA = 'dbo' and
 COLUMNPROPERTY(object_id(TABLE_NAME), COLUMN_NAME, 'IsIdentity') = 1
 ORDER BY

 TABLE_NAME

lunes, 5 de septiembre de 2016

“SUSPENDED STATUS” - Estudiando los Waiting Task y Waiting Stats -


   Amigos hemos hablado en el anterior artículo respecto de los distintos estados en los que se pueden encontrar las sesiones abiertas.
 Hay un estado en particular que genera muchas consultas por parte de uds y tiene que ver con el estado “Suspended”.
   La pregunta que se repite suele ser la siguiente. “Cómo es que la query que corre bajo la sesión nº xx se encuentra en estado “suspended” si veo con el sp_who2, (o con el active monitor etc), que soy el único que está atacando la base de datos y además mi  isolation level  lo seteo con el hint with (nolock)?
   La respuesta es la siguiente…

   NO se trata de que nuestra query no pueda ser resuelta por estar lockeada por otro proceso nuestra tabla/base de datos a la que queremos acceder..;  Lo que ocurre realmente es que nuestra query está esperando por la liberación de recursos del sistema para poder ser resuelta. (ejemplo memoria, procesador, i/o). Recursos lógicos o físicos…
  Entendamos que los estados “suspended” son inevitables en el sql server puesto que el scheduler va organizando y dando permisos de ejecución a los spids bajo el lema “primero entrado, primero salido”.      Cuándo un spid entra en estado “suspended”? cuando está siendo ejecutado (estado running) y tiene que esperar por  la liberación de algún recurso físico o lógico del sistema. En ese caso, el “scheduler” lo flaguea como “suspended” y le da el estado “running” a otro proceso que esté en cola, es decir, que tenga el estado “runnable”.
   Qué debería preocuparnos entonces de un estado suspended? Que el mismo se transforme en una constante y que se prolongue en el tiempo provocando time outs, bloqueos o lentitud considerable de nuestro sistema de base de datos.
   Qué podemos hacer para evitar este tipo de espera, cuando se transforman en algo reiterado, que generan tantas molestias y quejas de los usuarios finales.? Pues sin lugar a dudas en primer lugar siguiendo las mejores prácticas (ver apartado “como minimizar la ocurrencia de bloqueos” del siguiente post del año 2015: http://gherrerasqlserver.blogspot.com.ar/2015/06/bloqueos-en-sql-server-que-son-como.html)
    El motivo de mi insistencia en revisar las mejores prácticas tiene que ver con un principio muy simple. Cuanto más rápido se resuelva una query, menos tiempo tendremos ocupado un recurso del sistema y por consecuencia lógica, más lejos estaremos de ver estos molestos estados “suspended”
    Ahora bien, como a todos nos ha ocurrido a medida que fuimos ganando peso en nuestra querida profesión de DBA, llega un día en que queremos saber “algo más” acerca de los motivos que están generando incómodas esperas a nuestros procesos, a pesar de entender que somos prolijos dba apegados a las mejores prácticas…

Les propongo para ello dos tipos de estudios a saber:

    1)   ESTUDIO “WAITING TASKS”  -  permiten entender el tipo de espera que está afectando a nuestro sistema cuando notamos al mismo especialmente lento, cuando una query no termina de devolver resultados mostrando un estado “suspended”,  cuando percibimos bloqueos, cuando recibimos una queja puntual de usuarios finales por times out etc.
   Es decir se trata de un estudio del “ahora” para tratar de entender y solucionar un problema específico cuyas consecuencias pueden ser las anteriormente descriptas

2   2)  ESTUDIO “WAITING STATS” -  (acumuladas desde el último reinicio de estadísticas).  con el objetivo de poder diagnosticar problemas de performance de nuestro sistema a partir del análisis de las estadísticas que nos hablan  de los tipos de espera que ocurren con mayor asiduidad en nuestro sistema.


   
1       1)      Query   “ESTUDIO “WAITING TASKS”  “

   Se trata de una query hecha en base al join de vistas del sistema que Microsoft nos ofrece a saber:
-          Sys.dm_os_waiting_task : informa acerca de las colas de tareas que esperan por un recurso
-          Sys.dm_exec_requests    : informa sobre cada solicitud recibida por el motor de bd.
-          Sys.dm_exec_sessions     : nos devuelve una fila por cada sesión abierta en el server.
-       Msdb.dbo.sysjobs (tabla):  informa los nombres de los Jobs (si el proceso en espera es un job)
  Esta query es  vital para entender cuáles son los problemas que pueden estar aquejando a nuestro sistema de base de datos ante time outs o bloqueos que estén ocurriendo en el momento.
   Verán, que entrega información valiosísima tal como: el nº de spid, el status, el tipo de espera, el nombre del job o proceso, la cantidad de ms de cpu que lleva consumidos, la cantidad de páginas de memoria, los ms desde que la sesión fue establecida, las lecturas y escrituras físicas y lógicas, la sesión que está bloqueando (si se trata de una sesión bloqueada) etc .
   Por último, y antes de dejarles la query, quiero aclararles que en ella filtro el “sesión_id > 49”, dado que son los sesión id que corresponden a procesos de usuarios (del 1 al 49) son sesión id del sistema.

-------------------------------------------------------------
-- Estudiar Waiting Task                     
-- Autor: Gustavo Herrera Sql Server Para Todos 
-------------------------------------------------------------
select
c.nt_user_name,
a.session_id,
c.status,
a.wait_type,
a.wait_duration_ms,
c.host_name,
c.program_name,
w.name as job_name,
c.cpu_time as 'cpu_session(ms)',
c.memory_usage as 'pages_memory_session_usage',
c.total_elapsed_time as 'time_since_session_was_established(ms)',
c.last_request_start_time,
c.last_request_end_time,
c.reads as 'reads(session)',
c.writes as 'writes(session)',
c.logical_reads as 'logical_reads(session)',
(select  [TEXT] from sys.dm_exec_sql_text(b.plan_handle)) as 'query',
a.blocking_session_id,
resource_description
---
from sys.dm_os_waiting_tasks as a  
--
left join sys.dm_exec_requests as
on a.waiting_task_address = b.task_address
--
left join sys.dm_exec_sessions as c
on (a.session_id = c.session_id)
--
left join msdb.dbo.sysjobs as--Devuelve el nombre del job
on
(substring(left(w.job_id,8),7,2)+
substring(left(w.job_id,8),5,2) +
substring(left(w.job_id,8),3,2) +
substring(left(w.job_id,8),1,2))=
substring(c.program_name,32,8)
--
where a.session_id > 49
order by a.session_id


La query devuelve resultados como este:




















 Para poner a prueba nuestra query , antes de ejecutarla contra el server he generado 2 queries que scanean tablas de millones de registros (sesión_id 56 y 57) y he corrido un job que actualiza una de esas tablas.
   El resultado es el que pueden ver en el cuadro de arriba.

  Acorde al tipo de wait task, una sesión puede verse reflejada tantas veces como thereads tenga asignados.
   A no desesperar luego ahondaremos en los distintos tipos de espera (wait ype)




2)  Query ESTUDIO “WAITING STATS”


    Se trata de una query hecha en base a la vista del sistema    sys.dm_os_wait_stats.
   A través de esta query podremos ver agrupados todos los waits y el porcentaje que representan del total de los waits del sistema ordenados de modo decreciente.
   Se han filtrado en esta query algunos tipos de waits considerados “no relevantes” 
   Listamos solamente los tipos de espera que al menos representan un % 1 de los tipos de espera que nuestro server ha tenido desde el último reinicio de estadísticas (*)


------------------------------------
-- ESTUDIO ESTADíSTICAS DE ESPERA --
-- ---------------------------------

-- Esta query debe ser ejecutada en un solo paso (1 y 2 al mismo tiempo)

--1) Armo una temporal con las estadísticas de espera acumuladas
WITH [WaitsStatsStudio] AS
   (SELECT
    [wait_type],
    [wait_time_ms] / 1000.0 AS [WaitS],
     [signal_wait_time_ms] / 1000.0 AS [SignalS],
    [waiting_tasks_count] AS [WaitCount],
    100.0 * [wait_time_ms] / SUM ([wait_time_ms]) OVER() AS [Percentage],
    ROW_NUMBER() OVER(ORDER BY [wait_time_ms] DESC) AS [RowNum]
    FROM sys.dm_os_wait_stats
    --
    WHERE [wait_type] NOT IN ('BROKER_EVENTHANDLER','BROKER_RECEIVE_WAITFOR',
        'BROKER_TASK_STOP', 'BROKER_TO_FLUSH','BROKER_TRANSMITTER','CHECKPOINT_QUEUE',
        'CHKPT', 'CLR_AUTO_EVENT','CLR_MANUAL_EVENT', 'CLR_SEMAPHORE','DBMIRROR_DBM_EVENT',
        'DBMIRROR_EVENTS_QUEUE','DBMIRROR_WORKER_QUEUE', 'DBMIRRORING_CMD','DIRTY_PAGE_POLL',
        'DISPATCHER_QUEUE_SEMAPHORE', 'EXECSYNC', 'FSAGENT','FT_IFTS_SCHEDULER_IDLE_WAIT',
        'FT_IFTSHC_MUTEX','HADR_CLUSAPI_CALL','HADR_FILESTREAM_IOMGR_IOCOMPLETION',
        'HADR_LOGCAPTURE_WAIT','HADR_NOTIFICATION_DEQUEUE','HADR_TIMER_TASK','HADR_WORK_QUEUE',
        'KSOURCE_WAKEUP', 'LAZYWRITER_SLEEP','LOGMGR_QUEUE', 'MEMORY_ALLOCATION_EXT','ONDEMAND_TASK_QUEUE',
        'PREEMPTIVE_XE_GETTARGETSTATE','PWAIT_ALL_COMPONENTS_INITIALIZED','PWAIT_DIRECTLOGCONSUMER_GETNEXT',
        'QDS_PERSIST_TASK_MAIN_LOOP_SLEEP', N'QDS_ASYNC_QUEUE','QDS_CLEANUP_STALE_QUERIES_TASK_MAIN_LOOP_SLEEP',
        'QDS_SHUTDOWN_QUEUE', 'REDO_THREAD_PENDING_WORK','REQUEST_FOR_DEADLOCK_SEARCH','RESOURCE_QUEUE',
        'SERVER_IDLE_CHECK','SLEEP_BPOOL_FLUSH','SLEEP_DBSTARTUP', 'SLEEP_DCOMSTARTUP','SLEEP_MASTERDBREADY',
        'SLEEP_MASTERMDREADY','SLEEP_MASTERUPGRADED', 'SLEEP_MSDBSTARTUP','SLEEP_SYSTEMTASK','SLEEP_TASK',
        'SLEEP_TEMPDBSTARTUP', 'SNI_HTTP_ACCEPT','SP_SERVER_DIAGNOSTICS_SLEEP', 'SQLTRACE_BUFFER_FLUSH',
        'SQLTRACE_INCREMENTAL_FLUSH_SLEEP','SQLTRACE_WAIT_ENTRIES', 'WAIT_FOR_RESULTS','WAITFOR', 'WAITFOR_TASKSHUTDOWN',
        'WAIT_XTP_RECOVERY', 'WAIT_XTP_HOST_WAIT', 'WAIT_XTP_OFFLINE_CKPT_NEW_LOG','WAIT_XTP_CKPT_CLOSE',
        'XE_DISPATCHER_JOIN','XE_DISPATCHER_WAIT', 'XE_TIMER_EVENT')
        AND [waiting_tasks_count] > 0)

-- 2  Listo aquellos Waits que me representan un %  mayor al 0.99 % del total --        
SELECT
MAX ([W1].[wait_type]) AS [Tipo Espera],
CAST (MAX ([W1].[Percentage]) AS DECIMAL (5,2)) AS [% Porcentaje],
MAX ([W1].[WaitCount]) AS [Q Ocurrencias],
CAST (MAX ([W1].[WaitS]) AS DECIMAL (16,2)) AS [Q Espera(segundos)],
CAST (MAX ([W1].[SignalS]) AS DECIMAL (16,2)) AS [Q Señal Espera (segundos)],
CAST ((MAX ([W1].[WaitS]) / MAX ([W1].[WaitCount])) AS DECIMAL (16,4)) AS [Avg Espera (segundos)],
CAST ((MAX ([W1].[SignalS]) / MAX ([W1].[WaitCount])) AS DECIMAL (16,4)) AS [Avg Señal Espera (segundos)]
FROM [WaitsStatsStudio] AS [W1]
INNER JOIN [WaitsStatsStudio] AS [W2]
ON [W2].[RowNum] <= [W1].[RowNum]
GROUP BY [W1].[RowNum]
having MAX( [W1].[Percentage] ) > 0.99;
GO  
   
 Veremos un resultado como el de la siguiente pantalla:




















(*)   Cada vez que querramos volver a cero el contador de estadísticas a nivel de server debemos correr esta sentencia:
1
2
DBCC SQLPERF (N'sys.dm_os_wait_stats', CLEAR);
GO

  Como verán, en “Tipos de Espera”,  tenemos una serie de descripciones que serán objeto del próximos posts..Pero no los quiero dejar sin una breve explicación de los mismos y en siguientes posts profundizamos les parece? Comencemos…

CXPACKET  .
Este tipo de espera indica la presencia de paralelismo en los planes de ejecución de las queries.                  Cuando ocurre este tipo de espera? Cuando una query tiene varios threads de ejecución paralelos y uno o más de ellos demora más tiempo que el resto en resolverse. Esto hace que el resto de los threads queden bloqueados a la espera de que los hilos tardíos terminen su tarea.
Si el CXPACKET está acompañado de Pegaloatch_xx waits puede ser un indicador de scaneo de tablas.
De lo contrario hay cosas por hacer, seteos por mejorar ..como por ejemplo el Cost Threshold Parallelism setting, mas será objeto de un futuro post. Lo prometo.

PAGEILOATCH_XX.
Indica que el Sql Server está esperando por una página que será leída desde el disco. Puede ser indicativos de problemas de I/O de disco o de problemas de memoria (tal vez haya demasiada lectura desde disco en lugar de lectura desde memoria). En la práctica ocurre ante largos scans en tablas. Casi nunca ocurren ante queries e idx eficientes.

ASINC NETWORK IO
Rara vez relacionado con problemas de red como su  nombre podría inferirlo suele deberse a esperas que el Sql Server hace detrás de una consulta pobrísima de un cliente o programa que trae un set enorme de datos, seguramente sin sentido o en la forma menos performante. (un select * from) sería un caso típico.

WRITELOG
Indica que el Log Mangement está aguardando por un flush hacia el disco. Puede indicar que el subsistema i/o no puede lidear con el volumen del flush de log . En sistemas con grandes volúmenes puede indicar la presencia de límites internos de flush log. Tal vez si este es el caso sea hora de de dividir la carga en múltiples bases de datos o incrementar nuestras transacciones (el tamaño de las mismas)

BROKER RECEIVE WAITFOR
El Servicce Broker está esperando por nuevos mensajes para su recepción

MSQL XP
El SqlSrv está aguardando por la finalización de la ejecución de un store procedure extendido. Tal vez pueda haber un error en nuestro código XP

OLEDB
Puede indicar una espera causada por un server linkeado o tal vez a algún producto que esté utilizando vistas del sistema para monitorear..

BACKUPIO
Indica esperas producidas por procesos de backup lentos (por ejemplo hechos a cintas o sistemas I/O poco eficientes)..

LCK_M_XX
Nos habla de un thread esperando por poder establecer un lockeo e indica problemas de bloqueo. Repasar las mejores prácticas (ver en este post link hacia las mismas)..

BACKUPBUFFER
Suele aparecer junto al BackupIo y muestra un thread de backup esperando por un buffer para hacer un write del backup dentro de El.

IO COMPLETION
Suele indicar problemas del subsistema de I/O. Habla de sobrecarga en el mismo.

PAGELATCH_XX
Se trata cuando una tarea está esperando para mover data desde el disco al buffer cache. Fallas de velocidad I/O, presión de memoria, falta de idx pueden ser algunos de los disparadores de este wait.

RESOURCE SEMAPHORE
Son queries esperando por su ejecución en memoria. Puede indicar presión de memoria o mucha concurrencia de carga.

LATCH
Un latch es un objeto que asegura la integridad de los objetos que residen en Memoria, particularmente de las páginas residentes. Por lo tanto un wait está indicando que hay al menos una tarea bloqueando otras tareas para evitar lectura o escritura.


Amigos os prometo que los próximos post estarán dedicados a profundizar en los distintos tipos de espera.

Como siempre quedo a vuestra disposición.

Espero que les sea de suma utilidad estas dos queries y que las puedan incorporar sus tareas habituales.

Saludos cordiales desde Argentina

Gustavo Herrera.