Showing posts with label SQL Server. Show all posts
Showing posts with label SQL Server. Show all posts

Monday, December 16, 2013

Identify your server's waits

Identifying the cause of your server’s waits is a great starting point for analyzing, at a
high level, why your queries are waiting and thus giving suboptimal performance.

Running the SQL script shown here will identify the top 10 causes of waiting on your server instance.

Use SSRS/Crystal Reports or .NET to create a nice dashboard showing this data in a friendly manner this will help you visualize the top offender(s) wait type(s).



















SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
WITH Waits AS
    (SELECT TOP 10
        wait_type,
        wait_time_ms / 1000.0 AS WaitS,
        (wait_time_ms - signal_wait_time_ms) / 1000.0 AS ResourceS,
        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 (
        'CLR_SEMAPHORE', 'LAZYWRITER_SLEEP', 'RESOURCE_QUEUE', 'SLEEP_TASK',
        'SLEEP_SYSTEMTASK', 'SQLTRACE_BUFFER_FLUSH', 'WAITFOR', 'LOGMGR_QUEUE',
        'CHECKPOINT_QUEUE', 'REQUEST_FOR_DEADLOCK_SEARCH', 'XE_TIMER_EVENT', 'BROKER_TO_FLUSH',
        'BROKER_TASK_STOP', 'CLR_MANUAL_EVENT', 'CLR_AUTO_EVENT', 'DISPATCHER_QUEUE_SEMAPHORE',
        'FT_IFTS_SCHEDULER_IDLE_WAIT', 'XE_DISPATCHER_WAIT', 'XE_DISPATCHER_JOIN', 'BROKER_EVENTHANDLER',
        'TRACEWRITE', 'FT_IFTSHC_MUTEX', 'SQLTRACE_INCREMENTAL_FLUSH_SLEEP',
        'BROKER_RECEIVE_WAITFOR', 'ONDEMAND_TASK_QUEUE', 'DBMIRROR_EVENTS_QUEUE',
        'DBMIRRORING_CMD', 'BROKER_TRANSMITTER', 'SQLTRACE_WAIT_ENTRIES',
        'SLEEP_BPOOL_FLUSH', 'SQLTRACE_LOCK')
    )
SELECT TOP 10
    W1.wait_type AS WaitType,  
    CAST (W1.Percentage AS DECIMAL(4, 2)) AS Percentage
FROM Waits AS W1
    INNER JOIN Waits AS W2 ON W2.RowNum <= W1.RowNum
GROUP BY W1.RowNum, W1.wait_type, W1.WaitS, W1.ResourceS, W1.SignalS, W1.WaitCount, W1.Percentage
HAVING SUM (W2.Percentage) - W1.Percentage < 95;

Friday, May 10, 2013

How to decrypt SQL Objects?

The other day I ran into the situation where I needed to troubleshoot an specific stored procedure from a Legacy Environment which was encrypted. I tried to find if anyone had the stored proc code without luck.

After searching for a while I found a post on Jon's Gurgul blog about how to do this (tested it in SQL 2005/2008). As you need to query sys.sysobjvalues, which can only be accessed when using the Dedicated Admin Connection (DAC) you need to connect this way. 

Here are the steps:

You can enable Dedicated Admin Connection (DAC) or physically connect to the server and use sqlcmd.

EXEC sp_configure 'remote admin connections', 1
GO
RECONFIGURE
GO

Then with this done open SSMS, choose File, New, Database Engine Query and set your servername to be admin:ServerName

The last step is to change the code lines to reference the object you want the underlying text for and then check the messages tab

SET @ObjectName = 'sp_encrypted'
SET @Schema = 'dbo'

Here is the code of the Script.
DECLARE @EncObj VARBINARY(MAX),@DummyEncObj VARBINARY(MAX),@ObjectNameType NVARCHAR(50),@ObjectNameStmTemplate NVARCHAR(4000),@Schema nVARCHAR(MAX),@ObjectName NVARCHAR(50),@TemplateObj NVARCHAR(max)
DECLARE @p INT,@p1 NVARCHAR(MAX),@p2 NVARCHAR(MAX),@QueryForDummyObj NVARCHAR(MAX),@C INT
SET NOCOUNT ON
SET @ObjectName = 'sp_encrypted'
SET @Schema = 'dbo'
--please set @Schema = null for database/server triggers if needed
IF EXISTS
(
SELECT 1 FROM syscomments WHERE [encrypted] = 1 AND [id]= OBJECT_ID(@Schema+'.'+@ObjectName) OR @Schema IS NULL
)
BEGIN
IF EXISTS
(
SELECT * FROM sys.dm_exec_connections ec JOIN sys.endpoints e
on (ec.[endpoint_id]=e.[endpoint_id])
WHERE e.[name]='Dedicated Admin Connection'
AND ec.[session_id] = @@SPID
)
BEGIN
SELECT TOP 1 @ObjectName=ObjectName,@ObjectNameType=ObjectType,@ObjectNameStmTemplate=ObjectStmTemplate,@EncObj = [imageval]
FROM
(
SELECT name ObjectName,
CASE WHEN [type] = 'P' THEN N'PROCEDURE'
WHEN [type] = 'V' THEN 'VIEW'
WHEN [type] IN ('FN','TF','IF') THEN N'FUNCTION'
WHEN [type] IN ('TR') THEN N'TRIGGER'
ELSE [type]
END ObjectType,
CASE WHEN [type] = 'P' THEN N'WITH ENCRYPTION AS'
WHEN [type] = 'V' THEN N'WITH ENCRYPTION AS SELECT 123 ABC'
WHEN [type] IN ('FN') THEN N'() RETURNS INT WITH ENCRYPTION AS BEGIN RETURN 1 END'
WHEN [type] IN ('TF') THEN N'() RETURNS @t TABLE(i INT) WITH ENCRYPTION AS BEGIN RETURN END'
WHEN [type] IN ('IF') THEN N'() RETURNS TABLE WITH ENCRYPTION AS RETURN SELECT 1 N'
WHEN [type] IN ('TR') THEN N' ON ' + OBJECT_NAME(ao.[parent_object_id]) + ' WITH ENCRYPTION FOR DELETE AS SELECT 1 N'
ELSE [type]
END ObjectStmTemplate,
sov.[imageval]
FROM sys.all_objects ao
INNER JOIN sys.sysobjvalues sov ON sov.[valclass] = 1 AND ao.[Object_id] = sov.[objid]
WHERE [type] NOT IN ('S','U','PK','F','D','SQ','IT','X','PC','FS','AF')
AND ao.[name] = @ObjectName
AND ao.[schema_id] = SCHEMA_ID(@Schema)
--Server Triggers
UNION ALL SELECT name [ObjectName],'TRIGGER' [type],N'ON ALL SERVER WITH ENCRYPTION FOR DDL_LOGIN_EVENTS AS SELECT 1' [ObjectStmTemplate],sov.[imageval] FROM sys.server_triggers st
INNER JOIN sys.sysobjvalues sov ON sov.[valclass] = 1 AND st.[Object_id] = sov.[objid]
WHERE name = @ObjectName
--Database Triggers
UNION ALL SELECT name [ObjectName],'TRIGGER' [type],N'ON DATABASE WITH ENCRYPTION FOR CREATE_TABLE AS SELECT 1' [ObjectStmTemplate],sov.[imageval] FROM sys.triggers dt
INNER JOIN sys.sysobjvalues sov ON sov.[valclass] = 1 AND dt.[Object_id] = sov.[objid] AND dt.[parent_class_desc] = 'DATABASE'
WHERE name = @ObjectName
) x

--SELECT @ObjectName,@ObjectNameType,@ObjectNameStmTemplate,@EncObj

--Chunks
SET @C = CEILING(DATALENGTH(@EncObj) / 8000.0)

--Alter the existing object, then revert so that we have the dummy object encrypted value
BEGIN TRANSACTION
SET @p = 1
SET @p1= N'ALTER'+SPACE(1)+@ObjectNameType+SPACE(1)+ISNULL((@Schema+'.'),'')+@ObjectName +SPACE(1)+@ObjectNameStmTemplate;
SET @p1=@p1+REPLICATE('-',4000-LEN(@p1))
SET @p2 = REPLICATE('-',4000)
SET @QueryForDummyObj = N'EXEC(@p1'
WHILE @p<=@C
BEGIN
SET @QueryForDummyObj=@QueryForDummyObj+N'+@f'
SET @p =@p +1
END
SET @QueryForDummyObj=@QueryForDummyObj+')'
EXEC sp_executesql @QueryForDummyObj,N'@p1 NVARCHAR(4000),@f VARCHAR(8000)',@p1=@p1,@f=@p2

SELECT @DummyEncObj = sov.[imageval]
FROM sys.all_objects ao
INNER JOIN sys.sysobjvalues sov ON sov.[valclass]=1 AND ao.[Object_id]=sov.[objid]
WHERE ao.[name]=@ObjectName AND (ao.[schema_id]=SCHEMA_ID(@Schema) OR @Schema IS NULL)

ROLLBACK TRANSACTION

--Replacement Text
SET @TemplateObj = N'CREATE'+SPACE(1)+@ObjectNameType+SPACE(1)+ISNULL((@Schema+'.'),'')+@ObjectName +SPACE(1)+@ObjectNameStmTemplate+REPLICATE('-',4000)
DECLARE @i INT
SET @i = 1
WHILE @i<@C
BEGIN
SET @TemplateObj=@TemplateObj+REPLICATE(N'-',4000)
SET @i =@i+1
END

----Simple Char Decrypt
--DECLARE @Pos INT
--SET @Pos=1
--WHILE @Pos<=DATALENGTH(@EncObj)/2
--BEGIN
--PRINT NCHAR(UNICODE(SUBSTRING(CAST(@EncObj AS NVARCHAR(MAX)),@Pos,1))^(UNICODE(SUBSTRING(@TemplateObj,@Pos,1))^UNICODE(SUBSTRING(CAST(@DummyEncObj AS NVARCHAR(MAX)),@Pos,1))))
--SET @Pos=@Pos+1
--END

----8000 Char Decrypt Strings
DECLARE @CNumber INT,@CEncObj NVARCHAR(MAX),@CDummyEnc NVARCHAR(MAX),@CPiece NVARCHAR(MAX),@CPosition INT,@CTemplateObj NVARCHAR(MAX)
SET @CNumber=1
WHILE @CNumber<=@C
BEGIN
SELECT @CEncObj=SUBSTRING(@EncObj,(@CNumber-1)*8000+1,8000)
SELECT @CDummyEnc=SUBSTRING(@DummyEncObj,(@CNumber - 1) * 8000+1,8000)
SELECT @CTemplateObj=SUBSTRING(@TemplateObj,0+((@CNumber-1)*4000),4000)
SET @CPiece=REPLICATE(N'-',(DATALENGTH(@CEncObj)/2))
SET @CPosition=1
WHILE @CPosition<=DATALENGTH(@CEncObj)/2
BEGIN
SET @CPiece=STUFF(@CPiece,@CPosition,1,NCHAR(UNICODE(SUBSTRING(@CEncObj,@CPosition,1))^(UNICODE(SUBSTRING(@CTemplateObj,@CPosition,1))^UNICODE(SUBSTRING(@CDummyEnc,@CPosition,1)))))
SET @CPosition=@CPosition+1
END
PRINT @CPiece
SET @CNumber=@CNumber+1
END
END
ELSE
BEGIN
PRINT 'Use a DAC Connection'
END
END
ELSE
BEGIN
PRINT 'Object not encrypted or not found'
END



Sunday, March 10, 2013

syspolicy_purge_history - PowerShell subsystem failed to load Error

Error Message: 
Step 3 of job 'syspolicy_purge_history' (0x92D690B2954DA942915A08224A906C93) cannot be run because the PowerShell subsystem failed to load.  The job has been suspended.

Cause:  Invalid location of SQLPS.exe file

Steps to fix:

1.     Search the location of SQLPS.exe file by using the following quey
SELECT * FROM msdb.dbo.syssubsystems WHERE start_entry_point ='PowerShellStart'
   
     2.     Go to the server and check whether the file ‘SQLPS.exe’ is located in the path as per step 1.

     3.      If the paths are different, enable 'allow updates' using the below script to be able to write into system databases. If they are the same go to step 6.

sp_configure 'allow updates', 1
RECONFIGURE WITH OVERRIDE 

    4.      Update the correct path.

UPDATE msdb.dbo.syssubsystems SET agent_exe='Enter Correct Full Path Here\SQLPS.exe' WHERE start_entry_point ='PowerShellStart'

    5.     Disable 'allow updates'

sp_configure 'allow updates', 0
RECONFIGURE WITH OVERRIDE 

   6.    Get the SQL Server name you are working on by running:  SELECT @@SERVERNAME

   7.    Go to the job properties and edit the 'Erase Phantom System Health Records' step.








Insert the value gathered from step 6.











8.    Restart SQL Agent Service.

9.    Re-run syspolicy_purge_history job.

Saturday, March 9, 2013

Error: 701, Severity: 17, State: 135 - There is insufficient system memory in resource pool 'default' to run this query.


A few days ago one of our customers started to complain their queries were failing because of the following error:

Error: 701, Severity: 17, State: 135 - There is insufficient system memory in resource pool 'default' to run this query.

In the SQL Server Error Log we could see a bunch of entries with the same error message which indicated the SQL Instance was having memory pressure issues. 

To give you a little bit of background, this SQL Instance had allocated only 1GB of Memory with only one User Database; for this particular scenario it was quit obvious to determine which database was consuming all the memory however when we have multiple databases on the same Instance it is important to determine which database is consuming the available memory.

The following script can be used to determine whether a database is hogging the buffer pool and should perhaps be moved to its own server or just increase the Maximum Server Memory Setting for the SQL Instance if available Memory in the server exists. 

*Note: Remember to leave enough memory to the operating system before Increasing Maximum Server Memory.


SET TRAN ISOLATION LEVEL READ UNCOMMITTED
SELECT
ISNULL(DB_NAME(database_id), 'ResourceDb') AS DatabaseName
, CAST(COUNT(row_count) * 8.0 / (1024.0) AS DECIMAL(28,2))
AS [Size (MB)]
FROM sys.dm_os_buffer_descriptors
GROUP BY database_id
ORDER BY DatabaseName

The solution for this case was just increasing the Maximum Server Memory Setting, we never saw those error entries again.