SQL SERVER – Clustered Index on Separate Drive From Table Location

How to improve performance of SQL Server Queries is a common topic of discussion among many of us. Much has been said, much has been discussed. Few days back, I had an interesting discussion with one of the Junior developers regarding performance improvement of SQL Server Queries. We discussed on how by using a separate hard drive for several database objects can right away improve performance. I suggested him that non clustered index and tempdb can be created on a separate disk to improve performance.

No sooner had I given my suggestion than I received a question – What will happen if we can create clustered index on a separate drive from the table on which it is built.

My answer is : No! It is not possible at all.

Let us first be clear about the difference between a clustered and a non clustered index.

Clustered Index

  • Only 1 allowed per table
  • Physically rearranges data in the table to conform to the index constraints
  • For use on columns that are frequently searched for ranges of data
  • For use on columns with low selectivity

Non-Clustered Index

  • Up to 249 (for SQL Server 2005) and 999 (for SQL Server 2008) allowed per table
  • Creates a separate list of key values with pointers to the location of the data in the data pages
  • For use on columns that are searched for single values
  • For use on columns with high selectivity

A table devoid of primary key index is called heap, and here data is not arranged in a particular order, which gives rise to issues that adversely affect performance. Data must be stored in some kind of order. If we put clustered index on it then the order will be forced by that index and the data will be stored in that particular order.

Reference : Pinal Dave (http://blog.sqlauthority.com)

SQL SERVER – Difference Between Candidate Keys and Primary Key

Let us first try to grasp the definition of the two keys.

Candidate Key – A Candidate Key can be any column or a combination of columns that can qualify as unique key in database. There can be multiple Candidate Keys in one table. Each Candidate Key can qualify as Primary Key.

Primary Key – A Primary Key is a column or a combination of columns that uniquely identify a record. Only one Candidate Key can be Primary Key.

One needs to be very careful in selecting the Primary Key as an incorrect selection can adversely impact the database architect and future normalization. For a Candidate Key to qualify as a Primary Key, it should be Non-NULL and unique in any domain. I have observed quite often that Primary Keys are seldom changed. I would like to have your feedback on not changing a Primary Key.

I have illustrates the difference between a candidate key and a primary key in SQL Server.

1 Introduction
2 An Example to Understand Keys
2.1 Select a key that does not contain NULL
2.2 Select a key that is unique and does not repeat
2.3 Make sure that Primary Key does not keep changing
3 Selection of Primary Key
4 Quick Note on Other Kinds of Keys
5 Summary

Read Complete Article Here

Reference : Pinal Dave (http://blog.SQLAuthority.com)

SQL SERVER – How to Drop Primary Key Contraint

One area that always, unfailingly pulls my interest is SQL Server Errors and their solution. I enjoy the challenging task of passing through the maze of error to find a way out with a perfect solution. However, when I received the following error from one of my regular readers, I was a little stumped at first! After some online probing, I figured out that it was actually syntax from MySql and not SQL Server. The reader encountered error when he ran the following query.

ALTER TABLE Table1
DROP PRIMARY KEY
GO

Msg 156, Level 15, State 1, Line 3
Incorrect syntax near the keyword ‘PRIMARY’.

As mentioned earlier, this syntax is for MySql, not SQL Server. If you want to drop primary key constraint in SQL Server, run the following query.

ALTER TABLE Table1
DROP CONSTRAINT PK_Table1_Col1
GO

Let us now pursue the complete example. First, we will create a table that has primary key. Next, we will drop the primary key successfully using the correct syntax of SQL Server.

CREATE TABLE Table1(
Col1 INT NOT NULL,
Col2 VARCHAR(100)
CONSTRAINT PK_Table1_Col1 PRIMARY KEY CLUSTERED (
Col1 ASC)
)
GO

/* For SQL Server/Oracle/MS ACCESS */
ALTER TABLE Table1
DROP CONSTRAINT PK_Table1_Col1
GO

/* For MySql */
ALTER TABLE Table1
DROP PRIMARY KEY
GO

I hope this example lucidly explains how to drop primary key. This, no doubt, is a very simple and basic explanation, but when I chanced upon the error message it aroused curiosity in me.  As you all know by now I love sharing new issues and ideas with my readers. So I have included this interesting error in my blog.

Let me have your feedback on this post and also, do feel free to share with me your ideas as well!

Reference : Pinal Dave (http://blog.SQLAuthority.com)

SQL SERVER – 2008 – Find Relationship of Foreign Key and Primary Key using T-SQL – Find Tables With Foreign Key Constraint in Database

While searching for how to find Primary Key and Foreign Key relationship using T-SQL, I came across my own blog article written earlier SQL SERVER – 2005 – Find Tables With Foreign Key Constraint in Database. It is really handy script and not found written on line anywhere. This is one really unique script and must be bookmarked. There may be situations when there is need to find out on relationship between Primary Key and Foreign Key.

I have modified my previous script to add schema name along with table name. It would be really great if any of you can improve on this script.

USE AdventureWorks;
GO
SELECT f.name AS ForeignKey,
SCHEMA_NAME(f.SCHEMA_ID) SchemaName,
OBJECT_NAME(f.parent_object_id) AS TableName,
COL_NAME(fc.parent_object_id,fc.parent_column_id) AS ColumnName,
SCHEMA_NAME(o.SCHEMA_ID) ReferenceSchemaName,
OBJECT_NAME (f.referenced_object_id) AS ReferenceTableName,
COL_NAME(fc.referenced_object_id,fc.referenced_column_id) AS ReferenceColumnName
FROM sys.foreign_keys AS f
INNER JOIN sys.foreign_key_columns AS fc
ON f.OBJECT_ID = fc.constraint_object_id
INNER JOIN sys.objects AS o ON o.OBJECT_ID = fc.referenced_object_id
GO

 

Reference : Pinal Dave (http://blog.SQLAuthority.com)

SQL SERVER – Observation – Effect of Clustered Index over Nonclustered Index

Note: This article is re-write of my previous article SQL SERVER – Observation – Effect of Clustered Index over Nonclustered Index. I have received so many request that re-write it as it is little confusing. I am going to re-write this with simpler words.

Query optimization is one art which is difficult to master. Just like any other art this requires creativity and imagination as well understanding of subject matter. Let us look at interesting observation which I came across.

First of all download the script from here and run it in SSMS.

Now enable Execution Plan (Using CTRL + M) in SSMS before running the script.

The simple objective of this whole exercise is to understand how clustered index and nonclustered indexes are associated with each other.

In our example we have one query which is not using any index. On the same table there is already nonclustered index created, which is also not being used. Now when we created clustered index on the same table, our query suddenly started to use nonclustered index which was so far it is not using. The interesting part of this is that query is using nonclustered index when clustered index is created on the same.

Now let us test the same thing with example.

USE [AdventureWorks]
GO
/* */
CREATE TABLE [dbo].[MyTable](
[ID] [int] NOT NULL,
[First] [nchar](10) NULL,
[Second] [nchar](10) NULL
)
ON [PRIMARY]
GO
/* Create Sample Table */
INSERT INTO [AdventureWorks].[dbo].[MyTable]
([ID],[First],[Second])
SELECT 1,'First1','Second1'
UNION ALL
SELECT 2,'First2','Second2'
UNION ALL
SELECT 3,'First3','Second3'
UNION ALL
SELECT 4,'First4','Second4'
UNION ALL
SELECT 5,'First5','Second5'
GO

Now let us create nonclustered index over this table.

/* Create Nonclustered Index over Table */
CREATE NONCLUSTERED INDEX [IX_MyTable_NonClustered]
ON [dbo].[MyTable]
(
[First] ASC,
[Second] ASC
) ON [PRIMARY]
GO

Run following two queries together.

/* Run following two queries together and observe the
result in by Enabling Actual Execution Plan (CTRL + M)
1st Query will use Table Scan
2nd Query will use Index Seek
*/
SELECT ID
FROM [MyTable]
WHERE First = 'First1' AND Second = 'Second1'
SELECT Second
FROM [MyTable]
WHERE First = 'First1' AND Second = 'Second1'
GO

nic SQL SERVER   Observation   Effect of Clustered Index over Nonclustered Index

It is clear from query that index applies to columns on which it is created. In our case as in WHERE condition we have same columns which are used in Index.
Query 1 – Does not use any index
Query 2 – Does nonclustered index seek

Now create Clustered Index over the same table.

/* Create Clustered Index over Table */
CREATE CLUSTERED INDEX [IX_MyTable_Clustered]
ON [dbo].[MyTable]
(
[ID] ASC
) ON [PRIMARY]
GO

Once again run above two same query and see the execution plan.

/* Run following two queries together and observe the
result in 1st Query will use Index Seek
2nd Query will use Index Seek
*/
SELECT ID
FROM [MyTable]
WHERE First = 'First1' AND Second = 'Second1'
SELECT Second
FROM [MyTable]
WHERE First = 'First1' AND Second = 'Second1'
GO

nic1 SQL SERVER   Observation   Effect of Clustered Index over Nonclustered Index

Query 1 – Does nonclustered index seek
Query 2 – Does nonclustered index seek

Clean up the database by running following script.

/* Clean up */
DROP TABLE [dbo].[MyTable]
GO

Let us go over our steps of whole exercise.
Step 1: We have one table and one nonclustered index.
Step 2: We ran Query 1 which does not use nonclustered index.
Step 3: We created clustered index over table.
Step 4: We ran Query 1 which now use nonclustered index.

What is puzzling and interesting is how come query suddenly started to use nonclustered query when clustered index is created on table?

Query 1 should not have used index which is for second query as there is no change in that index or query1. Additionally, Query 1 is not even retrieving the column which is in nonclustered index. We created clustered index on column used in Query 1, so it should make Query 1 to use that clustered index but instead it is using nonclustered index which was already created and available to use earlier.

The question is : The question is why this has happened? If Query can use nonclustered index why did it has to wait for clustered index to be created?

Answer:
The reason for this is that every nonclustered index refers to clustered index internally. When clustered index is created on table it reorganizes the table in the physical order of the clustered index. When there is no clustered index created on table at that time all nonclustered index points to data in the table to retrieve the data, however once clustered index is created all the nonclustered indexes are reorganized and they point to clustered index. This effect is creating index seek operation on nonclustered index. In our example column on which clustered index is created is in SELECT clause and WHERE clause contains columns which are used in nonclustered index, which is creating the effect which we have observed.

Let me know what do you think about this re-written article, it should be clear now what I am trying to suggest. Again, I am looking forward to your feedback about this subject. I will be discussing this in next UG meeting which is today. Please leave a not to me and we can go over this article on goto meeting or live meeting.

Reference: Pinal Dave (http://blog.SQLAuthority.com)

SQL SERVER – Introduction to Force Index Query Hints – Index Hint – Part2

In my previous article SQL SERVER – Introduction to Force Index Query Hints – Index Hint I have discussed regarding how we can use Index Hints with any query. I just received email from one of my regular reader that are there any another methods for the same as it will be difficult to read the syntax of join.Yes, there is alternate way to do the same using OPTION clause however, as OPTION clause is specified at the end of the query we have to specify which table the index hint is put on.

Example 1: Using Inline Query Hint

USE AdventureWorks
GO
SELECT c.ContactID
FROM Person.Contact c
WITH (INDEX(AK_Contact_rowguid))
INNER JOIN Person.Contact pc
WITH (INDEX(PK_Contact_ContactID))
ON c.ContactID = pc.ContactID
GO

Example 2: Using OPTION clause

USE AdventureWorks
GO
SELECT c.ContactID
FROM Person.Contact c
INNER JOIN Person.Contact pc
ON c.ContactID = pc.ContactID
OPTION (TABLE HINT(c, INDEX (AK_Contact_rowguid)),
TABLE HINT(pc, INDEX (PK_Contact_ContactID)))
GO

Reference : Pinal Dave (http://blog.SQLAuthority.com)

SQL SERVER – Introduction to Force Index Query Hints – Index Hint

This article, I will start with disclaimer instead of having it at the end of article.

“SQL Server query optimizer selects the best execution plan for a query, it is recommended to use query hints by experienced developers and database administrators in case of special circumstances.”

When any query is ran SQL Server Engine determines which index has to be used. SQL Server makes uses Index which has lowest cost based on performance. Index which is the best for performance is automatically used. There are some instances when Database Developer is best judge of the index used. DBA can direct SQL Server which index to be used to execute query.

Example 1 : SQL Server using default index

USE AdventureWorks
GO
SELECT *
FROM Person.Contact
GO

indexhint1 SQL SERVER   Introduction to Force Index Query Hints   Index Hint

Example 2: SQL Server using forced index

USE AdventureWorks
GO
SELECT ContactID
FROM Person.Contact WITH (INDEX(AK_Contact_rowguid))
GO

indexhint2 SQL SERVER   Introduction to Force Index Query Hints   Index Hint

Example 3: SQL Server using different index for different/same tables

USE AdventureWorks
GO
SELECT c.ContactID
FROM Person.Contact c
WITH (INDEX(AK_Contact_rowguid))
INNER JOIN Person.Contact pc
WITH (INDEX(PK_Contact_ContactID))
ON c.ContactID = pc.ContactID
GO

indexhint3 SQL SERVER   Introduction to Force Index Query Hints   Index Hint

Reference : Pinal Dave (http://blog.SQLAuthority.com)

SQL SERVER – Observation – Effect of Clustered Index over Nonclustered Index

Today I came across very interesting observation while I was working on query optimization. Let us run the example first. Make sure to to enable Execution Plan (Using CTRL + M) before running comparison queries.

USE [AdventureWorks]
GO
/* */
CREATE TABLE [dbo].[MyTable](
[ID] [int] NOT NULL,
[First] [nchar](10) NULL,
[Second] [nchar](10) NULL
)
ON [PRIMARY]
GO
/* Create Sample Table */
INSERT INTO [AdventureWorks].[dbo].[MyTable]
([ID],[First],[Second])
SELECT 1,'First1','Second1'
UNION ALL
SELECT 2,'First2','Second2'
UNION ALL
SELECT 3,'First3','Second3'
UNION ALL
SELECT 4,'First4','Second4'
UNION ALL
SELECT 5,'First5','Second5'
GO

Now let us create nonclustered index over this table.

/* Create Nonclustered Index over Table */
CREATE NONCLUSTERED INDEX [IX_MyTable_NonClustered]
ON [dbo].[MyTable]
(
[First] ASC,
[Second] ASC
) ON [PRIMARY]
GO

Run following two queries together.

/* Run following two queries together and observe the
result in by Enabling Actual Execution Plan (CTRL + M)
1st Query will use Table Scan
2nd Query will use Index Seek
*/
SELECT ID
FROM [MyTable]
WHERE First = 'First1' AND Second = 'Second1'
SELECT Second
FROM [MyTable]
WHERE First = 'First1' AND Second = 'Second1'
GO

nic SQL SERVER   Observation   Effect of Clustered Index over Nonclustered Index

It is clear from query that index applies to columns on which it is created. In our case as in WHERE condition we have same columns which are used in Index.

Now create Clustered Index over the same table.

/* Create Clustered Index over Table */
CREATE CLUSTERED INDEX [IX_MyTable_Clustered]
ON [dbo].[MyTable]
(
[ID] ASC
) ON [PRIMARY]
GO

Once again run above two same query and see the execution plan.

/* Run following two queries together and observe the
result in 1st Query will use Index Seek
2nd Query will use Index Seek
*/
SELECT ID
FROM [MyTable]
WHERE First = 'First1' AND Second = 'Second1'
SELECT Second
FROM [MyTable]
WHERE First = 'First1' AND Second = 'Second1'
GO

nic1 SQL SERVER   Observation   Effect of Clustered Index over Nonclustered Index

Clean up the database by running following script.

/* Clean up */
DROP TABLE [dbo].[MyTable]
GO

Interesting part of above execution plan is now both queries are using nonclustered index scan. Logically first query should have not used index which is for second query as it was retrieving the column which was not in the nonclustered index. However, it did used the nonclustered index and only difference between our first execution and second execution is that we have created clustered index over the column which is retrieved in the first query.

The question is : The question is why this has happened?

In summary : A query which is not using nonclustered index to retrieve results used nonclustered index when clustered index created on the column which is retrieved.

The reason for this happening is that every nonclustered index refers to clustered index internally. When clustered index is created on table it reorganizes the table in the physical order of the clustered index. When there is no clustered index created on table at that time all nonclustered index points to data in the table to retrieve the data, however once clustered index is created all the nonclustered indexes are reorganized and they point to clustered index. This effect is creating index seek operation on nonclustered index in our case as column on which clustered index is created is in SELECT clause and WHERE clause contains columns which are used in nonclustered index.

Let me know what do you think about this article. It may be possible I have not explained this problem properly so I suggest if my readers can rewrite this part of problem and send it to me and I can include their documentation here.

Reference : Pinal Dave (http://blog.SQLAuthority.com)

SQL SERVER – Interesting Observation about Order of Resultset without ORDER BY

Today I observed very interesting little thing about SQL Server and I felt that I should share this with my readers.

I ran following two queries and found that I am getting different result-set. When I carefully observed I found that actually the result was same but order of the records returned is different.

USE AdventureWorks
GO
SELECT ContactID
FROM Person.Contact
GO
SELECT *
FROM Person.Contact
GO

orderof1 SQL SERVER   Interesting Observation about Order of Resultset without ORDER BY

This particular thing interested me. I knew that when “ORDER BY” is not used order of the table is not guaranteed but I was not able to reproduce simple example for the same. Every time when I countered example of different order without using ORDER BY it was very complex and not easy to explain.

Now let us discuss why the order is different even though ORDER BY clause is not used. It is common belief that when ORDER BY clause is not used it gives result following primary key index. However, it is not true always. The sentenced to remember is:

There is no order unless ORDER BY is used.

If ORDER BY clause is not used what is the SQL Server’s logic of returning the result-set. From example above it is clear that SQL Server for sure does not use Index always. In fact SQL Server uses index which gives fastest result. SQL Server Query optimizer is built with keeping performance in focus. Query optimizer always returns results using any method which is optimized for performance.

Let us observe following execution plan for the same example. This really helps us to understand what is going on behind the scene.

orderof SQL SERVER   Interesting Observation about Order of Resultset without ORDER BY

When SELECT ContactID is used, it uses non-clustered index to return the results, where as for SELECT * it uses clustered index to return the results. Even though clustered index is used to return result in second statement, results returned using non-clustered is faster and its costs of query execution is lesser than clustered index scan.

Summary of our experiment suggests that clustered index is not always faster and efficient than non-clustered index. When ORDER BY clause is not used similar query can return different result-set.

I would like to know your opinion on this subject.

Reference : Pinal Dave (http://blog.SQLAuthority.com)

SQL SERVER – Guidelines and Coding Standards Complete List Download

SQL SERVER – Guidelines and Coding Standards complete List Download

Coding standards and guidelines are very important for any developer on the path of successful career. A coding standard is a set of guidelines, rules and regulations on how to write code. Coding standards should be flexible enough or should take care of the situation where they should not prevent best practices for coding. They are basically the guidelines that one should follow for better understanding.

The concept behind implementing coding standards and guidelines, is that the consistency and uniformity in programming so that if multiple people are working on the same code, it becomes easier to communicate, share with or understand each other’s work.

With the goal of promoting good coding standards and guidelines I have created document which can guide developers.

SQL SERVER – Guidelines and Coding Standards Part – 1

SQL SERVER – Guidelines and Coding Standards Part – 2

SQL SERVER – Guidelines and Coding Standards complete List Download

Reference : Pinal Dave (http://blog.SQLAuthority.com)