How indexes work for below queries? - sql-server

I have created the below table with primary key:
create table test2
(id int primary key,name varchar(20))
insert into test2 values
(1,'mahesh'),(2,'ram'),(3,'sham')
then created the non clustered index on it.
create nonclustered index ind_non_name on test2(name)
when I write below query it will always you non clustered indexes in query execution plan.
select COUNT(*) from test2
select id from test2
select * from test2
Could you please help me to understand why it always use non clustered index even if we have clustered index on table?
Thanks in advance.

Basically when you create a non-clustered index on name, the index actually contains name and id, so it kind of contains all the table itself.
If you add another field like this:
create table test4
(id int primary key clustered,name varchar(20), name2 varchar(20))
insert into test4 values
(1,'mahesh','mahesh'),(2,'ram','mahesh'),(3,'sham','mahesh')
create nonclustered index ind_non_name on test4(name)
You'll see that some of the queries will start using the clustered index.

In your case the indexes are pretty much the same thing, since clustered index also contains the data, your clustered index is id, name and non clustered indexes contain the clustering key, so the non-clustered index is name, id.
You don't have any search criteria, so no matter which index is used, it must be scanned completely anyhow, so why should it actually use the clustered index?
If you add third field you your table, then at least select * will use clustered index.

You are confusing Primary Keys with clustering keys. They are not the same. You will need to explicitly create the clustering key.
To create the clustering key on the primary key in the create statement:
create table test2
(id int ,name varchar(20)
constraint PK_ID_test2 primary key clustered(id))
To add the clustering key to what you have already:
ALTER TABLE test2
ADD CONSTRAINT PK_ID_test2 primary key clustered(id)

Related

Unique constraint and index

I have a table in SQL Server containing some user related info where the primary key is id (auto increment by 1) and has a column named userId. Each user can only has one record in the table, so I have added a unique constraint on column userId. As per SQL Server docs, SQL Server will automatically create an index for the unique constraint column.
For the usage on the table, there can be many update and insert operations, as well as select operations, and that's where my questions arise.
I see that the index that got created automatically by SQL Server on the unique constraint column is a non-clustered index, where it is good for update and insert operations, but for select operation, it is not as fast as the clustered index. (ref. differences-between-a-clustered-and-a-non-clustered-index)
For this table, there can be many select by userId operations. From the performance perspective, should a clustered index on userId be created, given that clustered index is the fastest for read operations ?
If yes, but a non-clustered index has already been automatically created on column userId, could a clustered index still be created on the userId column? (I have found some similar question, from the answers, it seem like if doing so, it will first search through the non-clustered index, then it will points to the clustered index and continue that search non-clustered-index-and-clustered-index-on-the-same-column)
Assuming your table was created in the following manner:
CREATE TABLE dbo.users
(
id int identity(1,1),
userId int,
userName varchar(100),
emailAddress varchar(100),
constraint PK_dbo_users primary key (Id)
);
alter table dbo.users
add constraint UNQ_dbo_users_userId UNIQUE(userId);
... then you already have a clustered index on "id" column by default.
A table can only have one clustered index, as Jonathon Willcock mentioned in the comments. So you cannot add another clustered index to userId column.
You also cannot recreate the clustered index to switch it to the userId column, as the constraints must much the existing constraint. Also, assuming there are foreign key references involved from other tables, you would have to drop the foreign keys before you can drop the users table.
Another option is to create a nonclustered covering index with an INCLUDE clause that contains all the columns needed for your query. This will avoid key lookups in the query plan.
For example:
create nonclustered index IX_dbo_users
on dbo.users (userId) include (id, userName, emailAddress);
Whether the PK and/or clustered index should be on userId or Id column depends on your users queries. If more queries, or more important queries, rely on "id" having clustered index, then keep it. Etc.
But if your table does not already have a clustered index, then yes, add it on userId column.

SQL SERVER: Unique Constraint Explanation

Could someone simplify the explanation of adding a UNIQUE CONSTRAINT to a column please.
When creating the key index does SQL SERVER copy ALL of the information in the row and add it to the index or just the data in the column with the applied UNIQUE CONSTRAINT?
I hope I explained that properly.
Any help will be greatly appreciated.
Lee.
EDIT**
Ok i think i get it?
CREATE TABLE dbo.test
(
Id int NOT NULL,
Name char(10) NOT NULL UNIQUE
);
INSERT INTO dbo.test (id, name) VALUES (1, 'Lee')
INSERT INTO dbo.test (id, name) VALUES (2, 'Paul')
INSERT INTO dbo.test (id, name) VALUES (3, 'Adam')
INSERT INTO dbo.test (id, name) VALUES (4, 'Henry')
In a clustered index the whole table would be sorted like
3, Adam
4, Henry
1, Lee
2, Paul
So with each additional INSERT the server would have to re-sort the entire table based on the name column?
In a nonclustered index there is another "table" that stores the sort?
When creating the key index does SQL SERVER copy ALL of the
information in the row and add it to the index or just the data in the
column with the applied UNIQUE CONSTRAINT?
There is no such a term as "key index".
Indexes can be clustered or non-clustered.
When you declare UNIQUE CONSTRAINT it's logical entity, but it's physically supported by unique index creation
When you create your unique constraint declaring it as clustered, clustered index will be created. If you don't mention clustered in your constraint definition or use explicite nonclustered, non-clustered index will be created.
Non-clustered index is a separate data structure where every row contains key columns.
On the other hand, clustered index (or better call it clustered table) is data itself + searching B-tree above it. In this case no separate structure is created, it's table itself that now is organized not as a heap but as ordered index.
UNIQUE CONSTRAINT will work just as UNIQUE INDEX. There are 2 ways:
With a clustered index the rows are stored physically on the disk in the same order as the index. (hence, only one clustered index is possible)
With a non clustered index there is a second list that has pointers to the physical rows. You can have many non clustered indexes, although each new index will increase the time it takes to write new records.
If you have both clustered and non clustered index, then non clustered index will point to the clustered index column.
THIS 'SO' answer will help you understand it a bit clear.
By default the unique constraint and Unique index will create a non
clustered index if you don't specify any different (and the PK will by
default be created as CLUSTERED if no conflicting clustered index
exists) but you can explicitly specify CLUSTERED/NONCLUSTERED for any
of them.

Necessary to create index on multi field primary key in SQL server?

Given the database table:
UserID (PK)
SomeTypeID (PK)
SomeSubTypeID (PK)
Data
And you wish to query:
SELECT Data FROM Table WHERE UserID = {0} AND SomeTypeID = {1} AND SomeSubTypeID = {2}
Would you need to create the index UserID, SomeTypeID, SomeSubTypeID or does the fact they form the primary key mean this is not needed?
If you created your primary key as:
CREATE TABLE TBL (UserID, SomeTypeID, SomeSubType, Data
CONSTRAINT PK PRIMARY KEY (UserID, SomeTypeID, SomeSubType))
Then the default index that is being created is a CLUSTERED index.
Usually (so not all times), when looking for data, you would want your queries to use a NON-CLUSTERED index to filter rows, where the columns you use to filter rows will form the key of the index and the information (column) that you return from those rows as an INCLUDED column, in this case DATA, like below:
CREATE NONCLUSTERED INDEX ncl_indx
ON TBL (UserID, SomeTypeID, SomeSubType) INCLUDE (Data);
By doing this, you're avoiding accessing the table data, through the CLUSTERED index.
But, you can specify the type of index that you want your PRIMARY KEY to be, so:
CREATE TABLE TBL (UserID, SomeTypeID, SomeSubType, Data
CONSTRAINT PK PRIMARY KEY NONCLUSTERED (UserID, SomeTypeID, SomeSubType));
Buuut, because you want this to be defined as a PRIMARY KEY then you are not able to use the INCLUDE functionality, so you can't avoid the disk lookup in order to get the information from the DATA column, which is where you basically are with having the default CLUSTERED index.
Buuuuuut, there's still a way to ensure the uniqueness that the Primary Key gives you and benefit from the INCLUDE functionality, so as to do as fewer disk I/O's.
You can specify your NONCLUSTERED INDEX as UNIQUE which will ensure that all of your 3 columns that make up the index key are unique.
CREATE UNIQUE NONCLUSTERED INDEX ncl_indx
ON TBL (UserID, SomeTypeID, SomeSubType) INCLUDE (Data);
By doing all of these then your table is going to be a HEAP, which is not a very good thing. If you've given it a good thought in designing your tables and decided that the best clustering key for your CLUSTERED INDEX is (UserID, SomeTypeID, SomeSubType), then it's best to leave everything as you currently have it.
Otherwise, if you have decided on a different clustering key then you can add this unique nonclustered index, if you're going to query the table as you said you will.
AS long as you use all the columns used in your primary key when filtering you don't need to create seperate indexes. Your primary key is ok in your example.
Think of creating seperate index if you plan to filter on one of the columns and not the others. For example: SELECT Data FROM Table WHERE UserID = {0}

Is Unique key Clustered or Non-Clustered Index in SQL Server?

I am new to SQL Server and while learning about clustered index, I got confused!
Is unique key clustered or a non-clustered index? Unique key holds only unique values in the column including null, so according to this concept, unique key should be a clustered index, right? But when I went through this article I got confused MSDN
When you create a UNIQUE constraint, a unique nonclustered index is
created to enforce a UNIQUE constraint by default. You can specify a
unique clustered index if a clustered index on the table does not
already exist.
Please help me to understand the concept in a better manner, Thank you.
There are three ways of enforcing uniqueness in SQL Server indexes.
Primary Key constraint
Unique constraint
Unique index (not constraint based)
Whether they are clustered or non clustered is orthogonal to whether or not the indexes are declared as unique using any of these methods.
All three methods can create a clustered or non clustered index.
By default the unique constraint and Unique index will create a non clustered index if you don't specify any different (and the PK will by default be created as CLUSTERED if no conflicting clustered index exists) but you can explicitly specify CLUSTERED/NONCLUSTERED for any of them.
Example syntax is
CREATE TABLE T
(
X INT NOT NULL,
Y INT NOT NULL,
Z INT NOT NULL
);
ALTER TABLE T ADD PRIMARY KEY NONCLUSTERED(X);
--Unique constraint NONCLUSTERED would be the default anyway
ALTER TABLE T ADD UNIQUE NONCLUSTERED(Y);
CREATE UNIQUE CLUSTERED INDEX ix ON T(Z);
DROP TABLE T;
For indexes that are not specified as unique SQL Server will silently make them unique any way. For clustered indexes this is done by appending a uniquefier to duplicate keys. For non clustered indexes the row identifier (logical or physical) is added to the key to guarantee uniqueness.
Unique index can be both clustered or non-clustered.
But if you have nullable column the NULL value should be unique (only 1 row where column is null).
If you want to store more then 1 NULLs you can create the index with filter "where columnName is not null".
well all the answers provided was very helpful, but still i would like to add some detailed answer so that i would be helpful for some others as well
A table can contain only one clustered index and a primary key can
be a clustered / non-clustered index.
Unique Key can be a clustered/non-clustered index as well,
below are some of the examples
Scenario 1 : Primary Key will default to Clustered Index
In this case we will create only Primary Key and when we check the kind of index created on the table we will notice that it has created clustered index automatically over it.
USE TempDB
GO
-- Create table
CREATE TABLE TestTable
(ID INT NOT NULL PRIMARY KEY,
Col1 INT NOT NULL)
GO
-- Check Indexes
SELECT OBJECT_NAME(OBJECT_ID) TableObject,
[name] IndexName,
[Type_Desc] FROM sys.indexes
WHERE OBJECT_NAME(OBJECT_ID) = 'TestTable'
GO
-- Clean up
DROP TABLE TestTable
GO
Scenario 2: Primary Key is defined as a Non-clustered Index
In this case we will explicitly defined Primary Key as a non-clustered index and it will create it as a non-clustered index. It proves that Primary Key can be non-clustered index.
USE TempDB
GO
-- Create table
CREATE TABLE TestTable
(ID INT NOT NULL PRIMARY KEY NONCLUSTERED,
Col1 INT NOT NULL)
GO
-- Check Indexes
SELECT OBJECT_NAME(OBJECT_ID) TableObject,
[name] IndexName,
[Type_Desc] FROM sys.indexes
WHERE OBJECT_NAME(OBJECT_ID) = 'TestTable'
GO
-- Clean up
DROP TABLE TestTable
GO
Scenario 3: Primary Key defaults to Non-Clustered Index with another column defined as a Clustered Index
In this case we will create clustered index on another column, SQL Server will automatically create a Primary Key as a non-clustered index as clustered index is specified on another column.
-- Case 3 Primary Key Defaults to Non-clustered Index
USE TempDB
GO
-- Create table
CREATE TABLE TestTable
(ID INT NOT NULL PRIMARY KEY,
Col1 INT NOT NULL UNIQUE CLUSTERED)
GO
-- Check Indexes
SELECT OBJECT_NAME(OBJECT_ID) TableObject,
[name] IndexName,
[Type_Desc] FROM sys.indexes
WHERE OBJECT_NAME(OBJECT_ID) = 'TestTable'
GO
-- Clean up
DROP TABLE TestTable
GO
Scenario 4: Primary Key defaults to Clustered Index with other index defaults to Non-clustered index
In this case we will create two indexes on the both the tables but we will not specify the type of the index on the columns. When we check the results we will notice that Primary Key is automatically defaulted to Clustered Index and another column as a Non-clustered index.
-- Case 4 Primary Key and Defaults
USE TempDB
GO
-- Create table
CREATE TABLE TestTable
(ID INT NOT NULL PRIMARY KEY,
Col1 INT NOT NULL UNIQUE)
GO
-- Check Indexes
SELECT OBJECT_NAME(OBJECT_ID) TableObject,
[name] IndexName,
[Type_Desc] FROM sys.indexes
WHERE OBJECT_NAME(OBJECT_ID) = 'TestTable'
GO
-- Clean up
DROP TABLE TestTable
GO
reference:the above details is been refrenced from this article

SQL Server : optimize constraint for perform a query bases on 2 columns

I am creating a table Brands with the following schema :
UserId
CarId
Brand
The UserId references the id of an user in the user table
The CarId references the id of a car in the car table
The only query that I will use is a search bases on these 2 columns, to get the corresponding brand.
So my question was about the constraint part, as I am a beginner, I would like to know which type of constraint to use (index, primary key, clustered or non clustered, on each field or on the 2 fields together) to have my query the more optimized possible.
This is my script right now :
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[Brands]') AND type in (N'U'))
BEGIN
CREATE TABLE [Brands]
(
UserId BIGINT NOT NULL
CONSTRAINT [FK_Brands_Users]
FOREIGN KEY REFERENCES [Users] (UserId),
CarId BIGINT NOT NULL
CONSTRAINT [FK_Brands_Cars]
FOREIGN KEY REFERENCES [Cars] (CarId),
Brand nvarchar(15),
);
END
GO
ALTER TABLE [Brands]
ADD CONSTRAINT [Unique_UserId_BrandId] UNIQUE(UserId, BrandId);
GO
I would create a primary key including both fields. When you define a primary key it automatically create a clustered index. Also your primary key has a unique constraint build in. Your table is now a heap the way you wrote it here above which is not good. You can additionally create an extra non-clustered index on CarId. Having an additional non-clustered index on UserId is not usefull I think. The column UserId can use the clustered index because it's the first field in the clustered index but I'm not sure about that.

Resources