简体   繁体   中英

SQL Server - Is creating an index with a unique constraint as one of the columns necessary?

I have the query below:

SELECT PrimaryKey
FROM dbo.SLA
WHERE SLAName = @input
AND FK_SLA_Process = @input2
AND IsActive = 1

And this is my index for this SLA table.

CREATE INDEX IX_SLA_SLAName_FK_SLA_Process_IsActive ON dbo.SLA (SLAName, FK_SLA_Process, IsActive) INCLUDE (SLATimeInSeconds)

However, the SLAName column is unique so it has a unique constraint/index. Is my created index an overkill? Do I still need it or will SQL Server use the index created on the unique column SLAName ?

It would be an "overkill" if your index would only be on SLAName , but you are also ordering by FK_SLA_Process and IsActive so queries that need needs columns will benefit more from your index and less if you just had the unique one.

So for a query like this:

SELECT PrimaryKey
FROM dbo.SLA
WHERE SLAName = 'SomeName'

Both index will yield the same results and there would be no point in yours. But for queries like:

SELECT PrimaryKey
FROM dbo.SLA
WHERE SLAName = 'SomeName'
AND FK_SLA_Process = 'Some Value'

Or

SELECT SLATimeInSeconds
FROM dbo.SLA
WHERE SLAName = 'SomeName'

Your index will be better than the unique one (2nd example is a covering index).

You should inspect which kind of SELECT you do to this table and decide if you need this one or not. Keep in mind that having many indexes might speed up selects but slow down inserts, updates and deletes.

Assuming you have a such table declaration:

CREATE TABLE SLA
(
   ID  INT PRIMARY KEY,
   SLAName VARCHAR(50) NOT NULL UNIQUE,
   fk_SLA INT,
   IsActive TINYINT
)

Under the hood we have two indexes:

CREATE TABLE [dbo].[SLA](
    [ID] [int] NOT NULL,
    [SLAName] [varchar](50) NOT NULL,
    [fk_SLA] [int] NULL,
    [IsActive] [tinyint] NULL,
PRIMARY KEY CLUSTERED 
(
    [ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, 
    ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY],
UNIQUE NONCLUSTERED 
(
    [SLAName] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, 
    ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO

So this query will have an index seek and has an optimal plan:

SELECT s.ID 
FROM dbo.SLA s 
WHERE s.SLAName = 'test'

Its query plan indicates index seek because we are searching by index UNIQUE NONCLUSTERED ([SLAName] ASC ) and don't use other columns in WHERE statement:

在此处输入图片说明

But if you add extra parameters into WHERE :

SELECT s.ID 
FROM dbo.SLA s 
WHERE s.SLAName = 'test'
AND s.fk_SLA = 1
AND s.IsActive = 1

Execution plan will have extra look up:

在此处输入图片说明

Lookup happens when index does not have necessary information. SQL Query engine has to get out from UNIQUE NONCLUSTERED index data structure to find data of columns fk_SLA and IsActive in your table SLA .

So your index is overkill as you have UNIQUE NONCLUSTERED index:

UNIQUE NONCLUSTERED 
(
    [SLAName] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, 
     ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

If SLAName column is unique and it has a unique constraint , any query that returns only one or 0 rows (all the queries with a point search that include SLAName = 'SomeName' condition) will use the unique index and make (maximum) one lookup in the base table.

Unless your queries have a range search like SLAName like 'SomeName%' there is no need in covering index because index search + 1 lookup is almost the same as only index search, and there is no need to waste space / maintain another index for such a miserable performance gain.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM