Archive

Archive for the ‘T SQL’ Category

SQL Error – The specified ‘@notify_email_operator_name’ is invalid (valid values are returned by sp_help_operator)

June 24, 2014 Leave a comment

 
Today while creating some SQL Jobs I faced following error:

Msg 14234, Level 16, State 1, Procedure sp_verify_job, Line 245
The specified ‘@notify_email_operator_name’ is invalid (valid values are returned by sp_help_operator).

The Job’s Script was created from PROD environment and as the same operator was not available on my DEV server, executing same script on DEV environment was throwing this error. So now how to fix this error?
 

–> One method is to check if an Operator already exist n DEV server and use it in your SQL Job Script:

USE [msdb]
GO
EXEC sp_help_operator
GO

–> If the Operator does not exist then create a new Operator by using following DDL query:

USE [msdb]
GO
EXEC msdb.dbo.sp_add_operator 
	@name = N'OperatorName',
	@enabled = 1,
	@email_address = N'SupportEmail@DomainName.com',
	@category_name = N'Uncategorized'
GO

… and use the Operator name in the Script that you got from PROD server, and update the below part of the DDL Script:

DECLARE @jobId BINARY(16)
EXEC @ReturnCode =  msdb.dbo.sp_add_job @job_name=N'Acquire_Data_Source1', 
	@enabled=1, 
	@notify_level_eventlog=0, 
	@notify_level_email=2, 
	@notify_level_netsend=0, 
	@notify_level_page=0, 
	@delete_level=0, 
	@description=N'No description available.', 
	@category_name=N'ESBIAcquisition', 
	@owner_login_name=N'DOMAIN\Account', 
	@notify_email_operator_name='Operatorname', -- <-- Here
	@job_id=@jobId OUTPUT

 

–> If you are not sure about the Operator name and just testing the Jobs in DEV or Test environment and don’t any email alerts then just assign NULL instead of the operator name like:

@notify_email_operator_name=NULL
 


Categories: SQL Errors Tags:

Identify potential free space in Database files before shrinking – TSQL Query

April 27, 2014 3 comments

Today someone in office asked me:

"How can I know how much free space might be left in a Database to Shrink 
before actually Shrinking it?"

 

–> I told it is simple, go to SSMS, select Database -> Right click -> select Task -> select Shrink -> select either Database/File.

DatabaseFreeSpace01
 

–> It will show you Available Free Space, of the whole Database or each mdf/ldf/ndf file(s).

DatabaseFreeSpace02
 

–> He said he already knows it, his real ask was:

"what if you've hundreds of Databases and want to know the stats for each 
of them? Is there any SQL Query which can give you this stats, so that you can 
run it against each or all Database?"

 

I opened SQL Profiler, ran it against the instance and again performed all manual steps defined above to check the Free space. After the Shrink File pop-up window appeared I went back to the Profiler and stopped it, which threw me lot of typical SQL Queries generated by SQL Server DB engine. I searched and found the desired query that I was looking for. I slightly tweaked the query according to my needs and here it is:

USE [AdventureWorks2012]
GO

select 
	db_name()			AS [DatabaseName],
	s.name				AS [DB_File_Name],
	s.physical_name		AS [FileName],
	s.size * CONVERT(float,8) AS [TotalSize],
	CAST(CASE s.type WHEN 2 
			THEN s.size * CONVERT(float,8) 
			ELSE dfs.allocated_extent_page_count*convert(float,8) 
		END AS float)	AS [UsedSpace],
	CASE s.type WHEN 2 
		THEN 0 
		ELSE s.size * CONVERT(float,8) - dfs.allocated_extent_page_count*convert(float,8) 
	END					AS [AvailableFreeSpace] 
from sys.database_files AS s 
left outer join sys.dm_db_file_space_usage as dfs 
	ON dfs.database_id = db_id() 
	AND dfs.file_id = s.file_id
where (s.drop_lsn IS NULL)

–> Output:

DatabaseFreeSpace03
 

To Shrink Database Files check my earlier blog post: https://sqlwithmanoj.wordpress.com/2011/07/02/shrink-database-shrink-file/


Query to check AlwaysON Replica Latency for the LSNs (Log Sequence Numbers) by using DMVs

April 11, 2014 Leave a comment

SELECT 
	 ag.NAME AS 'AG Name'
	,ar.replica_server_name AS 'AG Replica Server'
	,DB_NAME(drs.database_id) AS 'Database Name'
	,CASE 
		WHEN ars.is_local = 1
			THEN N'LOCAL'
		ELSE 'REMOTE'
	END AS 'Is AG Replica Local'
	,CASE 
		WHEN ars.role_desc IS NULL
			THEN N'DISCONNECTED'
		ELSE ars.role_desc
	END AS 'AG Replica Role'
	,ar.availability_mode_desc AS 'Sync Mode'
	,drs.synchronization_state_desc AS SyncState
	,agl.dns_name AS 'Listener Name'
	,drs.last_hardened_lsn
	,drs.last_hardened_time
	,datediff(s, last_hardened_time, getdate()) / 60 AS 'Seconds Behind Primary'
	,drs.last_commit_time

FROM sys.availability_groups AS ag 

INNER JOIN sys.availability_replicas AS ar 
ON ag.group_id = ar.group_id

INNER JOIN sys.dm_hadr_availability_replica_states AS ars 
ON ar.replica_id = ars.replica_id

INNER JOIN sys.dm_hadr_database_replica_states drs 
ON ag.group_id = drs.group_id
AND drs.replica_id = ars.replica_id

INNER JOIN sys.availability_group_listeners AS agl
ON agl.group_id = ars.group_id

ORDER BY datediff(s, last_hardened_time, getdate()) DESC;

SQL Trivia – Find second (or nth) Highest Salary or Marks

January 5, 2014 Leave a comment

At a beginner level this is the most basic and widely asked SQL Interview Question, and I’ve seen many people talk about this when you ask them to ask a basic SQL question.

Or, I could say it’s a tollgate to judge if a candidate knows basic SQL or not 🙂

So, here on demand of lot of people who ping me or email me for this, I’ve drafted this post on various ways or Queries to get the desired results.
 

–> I’ll create a dummy dbo.Employee table and populate with some dummy records (all these are my school/college friends):

USE tempdb
GO

CREATE TABLE dbo.Employee (
	EmpID INT PRIMARY KEY NOT NULL,
	EmpName VARCHAR(100),
	Salary Money
)
GO

INSERT INTO dbo.Employee
SELECT 1,  'Manoj',   20000
UNION ALL
SELECT 2,  'Saurabh', 50000
UNION ALL
SELECT 3,  'Kanchan', 30000
UNION ALL
SELECT 4,  'Hema',    10000
UNION ALL
SELECT 5,  'Bhanu',   60000
UNION ALL
SELECT 6,  'Prakash', 80000
UNION ALL
SELECT 7,  'Vivek',   40000
UNION ALL
SELECT 8,  'Ramesh',  55000
UNION ALL
SELECT 9,  'Kapil',   65000
UNION ALL
SELECT 10, 'Dev',     90000
GO

select * from dbo.Employee order by Salary DESC
GO

 

–> We will check for these conditions, 2nd highest & nth highest salary records from the above query, as shown below:

2nd highest is: 6, Prakash, 80000.00
5th highest is: 8, Ramesh,  55000.00
7th highest is: 7, Vivek,   40000.00

 

–> 2nd Highest Salary:

1. For SQL Server 2005 and +

;WITH CTE AS (
SELECT 
	EmpID, EmpName, Salary, 
	ROW_NUMBER() OVER(ORDER BY Salary DESC) as RN
FROM dbo.Employee
)
SELECT EmpID, EmpName, Salary
FROM CTE
WHERE RN = 2
GO

2. For SQL Server 2000

SELECT TOP 1 EmpID, EmpName, Salary
FROM (SELECT TOP 2 EmpID, EmpName, Salary 
	  FROM dbo.Employees 
	  ORDER BY Salary DESC
) X
ORDER BY Salary ASC
GO

 

–> nth Highest Salary: Just parametrize the numbers

1. For SQL Server 2005 +

DECLARE @n INT = 5

;WITH CTE AS (
SELECT 
	EmpID, EmpName, Salary, 
	ROW_NUMBER() OVER(ORDER BY Salary DESC) as RN
FROM dbo.Employee
)
SELECT EmpID, EmpName, Salary
FROM CTE
WHERE RN = @n
GO

2. For SQL Server 2000

DECLARE @n INT = 5

SELECT TOP 1 EmpID, EmpName, Salary
FROM (SELECT TOP (@n) EmpID, EmpName, Salary 
	  FROM dbo.Employees 
	  ORDER BY Salary DESC
) X
ORDER BY Salary ASC
GO

--// Final Cleanup
DROP TABLE dbo.Employee
GO

 

There are lot other ways also to get the same results and you can come up with different Queries with more optimizations.

Please do let me know if you have any comments and suggestions, thanks!

Memory Optimized Indexes | Hash vs Range Indexes – SQL Server 2014

December 20, 2013 3 comments

In SQL Server 2014 for In-Memory tables there are lot of changes in DDLs compared with normal Disk Based Tables. In-Memory Tables related changes we’ve seen in previous posts, check [here]. Here we will see Memory Optimized Index related changes and few important things to take care before designing your Tables and Indexes.
 

–> Some of the main points to note are:

1. Indexes on In-Memory tables must be created inline with CREATE TABLE DDL script only.

2. These Indexes are not persisted on Disk and reside only in memory, thus they are not logged. As these Indexes are not persistent so they are re-created whenever SQL Server is restarted. Thus In-Memory tables DO NOT support Clustered Indexes.

3. Only two types of Indexes can be created on In-Memory tables, i.e. Non Clustered Hash Index and Non Clustered Index (aka Range Index). So there is no bookmark lookup.

4. These Non Clustered Indexes are inherently Covering, and all columns are automatically INCLUDED in the Index.

5. Total there can be MAX 8 Non Clustered Indexes created on an In-Memory table.
 

–> Here we will see how Query Optimizer uses Hash & Range Indexes to process query and return results:

1. Hash Indexes: are used for Point Lookups or Seeks. Are optimized for index seeks on equality predicates and also support full index scans. Thus these will only perform better when the predicate clause contains only equality predicate (=).

2. Range Indexes: are used for Range Scans and Ordered Scans. Are optimized for index scans on inequality predicates, such as greater than or less than, as well as sort order. Thus these will only preform better when the predicate clause contains only inequality predicates (>, <, =, BETWEEN).
 

–> Let’s check this by some hands-on code. We will create 2 similar In-Memory tables, one with Range Index and another with Hash Index:

-- Create In-Memory Table with simple NonClustered Index (a.k.a Range Index):
CREATE TABLE dbo.MemOptTable_With_NC_Range_Index
(
    ID INT NOT NULL
        PRIMARY KEY NONCLUSTERED,
    VarString VARCHAR(200) NOT NULL, 
    DateAdded DATETIME NOT NULL
) WITH (
	MEMORY_OPTIMIZED = ON, 
	DURABILITY = SCHEMA_AND_DATA
)
GO

-- Create In-Memory Table with NonClustered Hash Index:
CREATE TABLE dbo.MemOptTable_With_NC_Hash_Index
(
    ID INT NOT NULL
        PRIMARY KEY NONCLUSTERED HASH WITH (BUCKET_COUNT = 10000),
    VarString VARCHAR(200) NOT NULL, 
    DateAdded DATETIME NOT NULL
) WITH (
	MEMORY_OPTIMIZED = ON, 
	DURABILITY = SCHEMA_AND_DATA
)
GO

 

–> Now we will Insert about 10k records on both the tables, so that we have good numbers of records to compare:

DECLARE @i INT = 1

WHILE @i <= 10000
BEGIN
	INSERT INTO dbo.MemOptTable_With_NC_Range_Index 
		VALUES(@i, REPLICATE('a', 200), GETDATE())

	INSERT INTO dbo.MemOptTable_With_NC_Hash_Index 
		VALUES(@i, REPLICATE('a', 200), GETDATE())

	SET @i = @i+1
END

 

–> Now check the Execution Plan by using equality Operator (=) on both the tables:

SELECT * FROM MemOptTable_With_NC_Hash_Index  WHERE ID = 5000 -- 4%
SELECT * FROM MemOptTable_With_NC_Range_Index WHERE ID = 5000 -- 96%

You will see in the Execution Plan image below that Equality Operator with Hash Index Costs you only 4%, but Range Index Costs you 96%.

SQLServer2014_Hash_vs_Range_1
 

–> Now check the Execution Plan by using inequality Operator (BETWEEN) on both the tables:

SELECT * FROM MemOptTable_With_NC_Hash_Index  WHERE ID BETWEEN 5000 AND 6000 -- 99%
SELECT * FROM MemOptTable_With_NC_Range_Index WHERE ID BETWEEN 5000 AND 6000 -- 1%

You will see in the Execution Plan image below that Inequality Operator with Range Index Costs you only 1%, but Hash Index Costs you 99%.

SQLServer2014_Hash_vs_Range_2
 

So, while designing In-Memory Tables and Memory Optimized Indexes you will need to see in future that how you will be going to query that table. It also depends upon various scenarios and conditions, so always keep note of these things in advance while designing your In-Memory Tables.
 

Update: Know more about In-Memory tables: