Unique Clustered Index - can I make non-unique without drop/create - sql-server

I have a unique clustered index that is causing replication problems (see "bounded updates"). Is there any way, short of dropping the clustered index, to make the index non-unique?

Is the clustered index also the primary key? If the clustered index is the primary key, then a unique clustered is also created. This mean you have to drop and create.
If the clustered index is not the primary key, you can use with drop existing to drop/create the index.
e.g.
create clustered index MyIndex on MyTable(MyColumn[s]) with(drop_existing=on);

Related

What is different between the two methods of generating cluster primary keys?

I have a Table to make a Clustered Primary Key.
CREATE TABLE dbo.SampleTable
(
C1 INT NOT NULL,
C2 INT NOT NULL )
First Way is making Primary Key index with Clustered index.
ALTER TABLE dbo.SampleTable ADD CONSTRAINT IDX_SampleTable PRIMARY KEY CLUSTERED (C1, C2)
Second Way is CREATE CLUSTERED INDEX after ADD CONSTRAINT PRIMARY KEY NONCLUSTERED about same columns.
ALTER TABLE dbo.SampleTable ADD CONSTRAINT IDX_SampleTable PRIMARY KEY NONCLUSTERED (C1, C2)
CREATE CLUSTERED INDEX IDX_SampleTable2 ON dbo.SampleTable (C1 ,C2) -- Can not create Same Name With above Constraint Name
Is there a difference in performance from the above two methods?
Is there a way do not recommend using it?
Yes, there is a difference. By specifying CLUSTERED, you instruct the database to store the data in a certain way. Basically, it enforces that subsequent indexes are stored on subsequent data blocks on the hard drive.
By creating a clustered primary key as in your first statement, all the data in the table will always have unique values in C1, C2 and the data is always stored in subsequent data blocks.
In the second example, you do NOT enforce this CLUSTERED behaviour through the primary key, but through a separate index. Though the effects are the same now, you might choose to remove (or temporarily disable) the index and then the data would no longer be guaranteed to get stored in a CLUSTERED fashion.
Bottom line: In practice these two statements are the same now, but might make a difference in the future because the CLUSTERED property is not integrated in the PK, but in a separate index.
Creating a Nonclustered Primary Key and then creating a Clustered index on the columns within the Primary key is not a good idea. Effectively you'll create 2 indexes on the columns (C1 and C2 in this case), however, it's very unlikely the nonclustered index will ever be used. This is because the Clustered Index is very likely going to be the first choice for the RDBMS, as the pages will be in the order of the Clustered Index. Also, when using a non-clustered index the data engine will still need to refer to the Clustered Index afterwards, to find out the exact location of the row (in the pages).
If you do want a clustered index on your Primary Key(s) then create the key as a Clustered Primary Key. This is not to say that your Primary Key should always be Clustered, but that is a very different subject.
This depends from your datas:
https://learn.microsoft.com/en-gb/sql/relational-databases/indexes/clustered-and-nonclustered-indexes-described?view=sql-server-2017
Clustered indexes sort and store the data rows in the table or view
based on their key values. These are the columns included in the index
definition. There can be only one clustered index per table, because
the data rows themselves can be stored in only one order.
So the clustered key influence the format of your physical data structure.

Multiple Clustered Indexes on a Single Table?

I thought we could only place one clustered index on one table, and put multiple non-clustered indexes on a table, but using the code below I can easily add more than one clustered index to my table.
CREATE CLUSTERED INDEX TBL_MULTI_LC_HIST ON dbo.TBL_MULTI_LC_HIST (ID,AsOfDate)
Is this completely wrong?
It isn't possible to create multiple clustered indexes for a single table. From the docs (emphasis mine):
Clustered indexes sort and store the data rows in the table or view based on their key values. These are the columns included in the index definition. There can be only one clustered index per table, because the data rows themselves can be stored in only one order.
For example this will fail:
CREATE TABLE Thing
(
Column1 INT NOT NULL,
Column2 INT NOT NULL
)
CREATE CLUSTERED INDEX IX1 ON dbo.Thing(Column1)
CREATE CLUSTERED INDEX IX2 ON dbo.Thing(Column2)
Error:
Cannot create more than one clustered index on table 'dbo.Thing'. Drop the existing clustered index 'IX1' before creating another.
Example: http://www.sqlfiddle.com/#!18/53a63/1
You can however have a single index with multiple columns in it which is perhaps where you are getting confused:
CREATE CLUSTERED INDEX IX3 ON dbo.Thing(Column1, Column2)
You can only have one clustered index. A "Clustered" index IS the row... it contains all the columns. Every other index would just contain a pointer to the clustered row. The key of the clustered index enforces an 'ordering' on the rows by default.
If there is no clustered index, then the rows are basically stored in a heap, with no order or structure.

Guid Non Clustered Index Sql Server 2012

I have some tables that have Guids as the PK. Guids must be the primary key as we will be working disconnected. I have added a INT Identity column that I will be adding the clustered index on for each table. What I want to ask after reading all the questions on Guids as PK -- Do I need to add a non clustered index on the Guid PK as well? Thanks.
Why not just use newsequentialid() rather than newid() and leave the clustered index on the PK?
But to answer your question, the primary key is always an index, so there's no need to create another one.

T-SQL Clustered Foreign Key

The "Create Table" grammar rather clearly does not allow me to specify a clustered foreign key constraint. In other words, this is illegal:
--keyword CLUSTERED must be removed before this will execute...
CREATE TABLE [Content](
[ID] [int] NOT NULL CONSTRAINT PK_Content_ID PRIMARY KEY,
ContentDefID int NOT NULL CONSTRAINT FK_Plugin_ContentDef FOREIGN KEY CLUSTERED REFERENCES ContentDef(ID)
)
GO
But I don't understand why it is illegal. ISTM that clustering a foreign-key would facilitate performance of paged-lookups. In other words, "give me child items 80 through 140 of parent ID 20".
Is there a rationale for this?
Update
Based on Oded and Tvanfosson feedback, I've found that the following works:
CREATE TABLE [Content](
[ID] [int] NOT NULL CONSTRAINT PK_Content_ID PRIMARY KEY,
ContentDefID int NOT NULL UNIQUE CLUSTERED CONSTRAINT FK_ContentDefContent FOREIGN KEY REFERENCES ContentDef(ID)
)
GO
But the above causes more problems than it solves. First, a "UNIQUE" foreign key forces my relationship to be one-to-one which I don't want. Second, this only works because it represents the creation of two separate constraints, rather than a single CLUSTERED FOREIGN KEY.
But this investigation is getting me closer to my answer. Evidently clustered indexes MUST be unique, as stated here on SO. Quoting:
If the clustered index is not a unique index, SQL Server makes any duplicate keys unique by adding an internally generated value called a uniqueifier
In particular, I think this answer covers it.
As others have explained, the clustered index does not have to be the primary key but it either has to be unique or SQL-Server adds a (not shown) UNIQUIFIER column to it.
To avoid this, you can make the clustered index unique by explicitly adding the primary key column to the clustered index, like below. The index will then be avaialbel to be used by the foreign key constraints (and for queries, like joining the two tables).
Notice, that as #Martin Smith has explained, the concepts of CONSTRAINT and INDEX are different. And the various DBMSs implement these in different ways. SQL-Server automatically creates an index for some constraints, while it doesn't for foreign key constraints. It's advised though to have an index that the constraint can use (when deleting or updating in the referenced table):
CREATE TABLE Content(
ID int NOT NULL,
ContentDefID int NOT NULL,
CONSTRAINT PK_Content_ID
PRIMARY KEY NONCLUSTERED (ID),
CONSTRAINT CI_Content
UNIQUE CLUSTERED (ContentDefID, ID),
CONSTRAINT FK_Plugin_ContentDef
FOREIGN KEY (ContentDefID) REFERENCES ContentDef(ID)
) ;
Is there a rationale for this?
You might as well ask why you can't create a CLUSTERED check constraint or a CLUSTERED default constraint.
A foreign key simply defines a logical constraint and has no indexes automatically created for it in SQL Server (this only happens for UNIQUE or PRIMARY KEY constraints). It is always the case in SQL Server that if you want the FK columns indexed you need to run a CREATE INDEX on the relevant column(s) yourself.
Therefore the concept of a CLUSTERED FOREIGN KEY doesn't make any sense. You can of course create a CLUSTERED INDEX on the columns making up the FK though as you indicate in your question.
You can only have one clustered index on a table. By default this will be the primary key column.
There are ways to change this - you will need to use PRIMARY KEY NONCLUSTERED and UNIQUE CLUSTERED FOREIGN KEY.
It seems you're conflating the ideas of the clustered index with keys (either primary or foreign). Why not just make the table and then specify its clustered index afterwards? (code copied from your first example and changed as little as possible)
CREATE TABLE [Content](
[ID] [int] NOT NULL CONSTRAINT PK_Content_ID PRIMARY KEY NONCLUSTERED,
ContentDefID int NOT NULL CONSTRAINT FK_Plugin_ContentDef FOREIGN KEY REFERENCES ContentDef(ID)
)
GO
CREATE CLUSTERED INDEX IX_Content_Clustered on Content(ContentDefID)
There's no need for you to make the clustered index unique

SQL Server: Alter a clustered primary index to an non-clustered

How do I alter a primary clustered index to become a non-clustured index. (Being a "secondary" table I want to use the clustured index for the foreign key column of the "header" table.)
This doen't work for me (error seems reasonable :)
DROP INDEX ClientUsers.PK_ClientUsers
CREATE UNIQUE CLUSTERED INDEX IDX_ClientUsers_Id ON ClientUsers(Id)
Msg 3723, Level 16, State 4, Line 7
An explicit DROP INDEX is not allowed on index 'ClientUsers.PK_ClientUsers'.
It is being used for PRIMARY KEY constraint enforcement.
I think you will have to:
Drop the FK
Drop the PK
Drop the clustered index
Recreate the PK
Recreate the FK
Recreate the clustered index on the FK column
and then optionally create a secondry index on the PK column
Have you tried dropping the PRIMARY KEY constraint on the table as well - then dropping the index - then re-adding both?
ALTER TABLE table_name DROP primary key

Resources