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.
Related
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.
It seems in SQL Server before version 2019, the clustering key/keys goes up to tree structure with not unique non-clustered index. With bigger and multiple clustering key/keys, you gain much more wider and taller tree that costs you more storage size and memory size.
Because of that we used to separate PK from clustered key my questions are
Have SQL Server 2019 and Azure changed in non-clustered indexing or not?
Heaps do not have clustering key/keys at all, what's the way of indexing in heaps?
Have SQL Server 2019 and Azure changed in non-clustered indexing or not
This behavior is older than many people on this site.
Because of that we used to separate PK from clustered
That is an almost-always-unnecessary micro-optimization.
Heaps do not have clustering key/keys at all, what's the way of indexing in heaps
Non-clustered non-unique indexes always have the row locator as index keys. For heaps the row locator is the ROWID (FileNo,PageNo,SlotNo).
If you want move the rows out from the leaf level of your wide PK, it's typically for a very large table. And so moving the rows to a clustered columstore index can be a good option. To do that just drop the clustered PK (this will leave the leaf level as a heap), create the CCI, and then recreate the PK as a nonclustered PK. eg
drop table if exists t
go
create table t(id int not null, a int, b int)
alter table t
add constraint pk_t
primary key clustered(id)
go
alter table t drop constraint pk_t
create clustered columnstore index cci_t on t
alter table t
add constraint pk_t
primary key nonclustered (id)
And if you have other non-clustered indexes drop them first, and only recreate them afterwords if you really need to. IE unique indexes, indexes supporting a foreign key, or indexes need to support specific queries. A CCI typically doesn't need lots of indexes since it's so efficient to scan.
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.
I have a table that I intended to partition by a nullable column.
This seems to work just fine except for the primary key. I get an error:
Partition columns for a unique index must be a subset of the index key
Create a primary key on a different filegroup. This doesn't work because it removes partitioning.
Skip the primary key all together and create a clustered index (non-unique). This won't work exactly because I need a primary key.
Any idea on how I can get a primary key on a partitioned table where the partition column is nullable? If not, I am open to suggestions on how to handle it another way.
Thanks in advance.
Not sure what really blocked you. You can create PK on your unique column, and have your partition column with nullable. Just not to only create unique cluster index on only PK column. When you need to create unique cluster index, add you PK column and the partition column together.
How do I switch off the default index on primary keys
I dont want all my tables to be indexed (sorted) but they must have a primary key
You can define a primary key index as NONCLUSTERED to prevent the table rows from being ordered according to the primary key, but you cannot define a primary key without some associated index.
Tables are always unsorted - there is no "default" order for a table and the optimiser may or may not choose to use an index if one exists.
In SQL Server an index is effectively the only way to implement a key. You get a choice between clustered or nonclustered indexes - that is all.
The means by which SQL Server implements Primary and Unique keys is by placing an index on those columns. So you cannot have a Primary Key (or Unique constraint) without an index.
You can tell SQL Server to use a nonclustered index to implement these indexes. If there are only nonclustered indexes on a table (or no indexes at all), you have a heap. It's pretty rare that this is what you actually want.
Just because a table has a clustered index, this in no way indicates that the rows of the table will be returned in the "order" defined by such an index - the fact that the rows are usually returned in that order is an implementation quirk.
And the actual code would be:
CREATE TABLE T (
Column1 char(1) not null,
Column2 char(1) not null,
Column3 char(1) not null,
constraint PK_T PRIMARY KEY NONCLUSTERED (Column2,Column3)
)
What does " I dont want all my tables to be sorted" mean ? If it means that you want the rows to appear in the order where they've been entered, there's only one way to garantee it: have a field that stores that order (or the time if you don't have a lot of transactions). And in that case, you will want to have a clustered index on that field for best performance.
You might end up with a non clustered PK (like the productId) AND a clustered unique index on your autonumber_or_timestamp field for max performance.
But that's really depending on the reality your're trying to model, and your question contains too little information about this. DB design is NOT abstract thinking.