Is a primary key automatically an index? - sql-server

If I run Profiler, then it suggests a lot of indexes like this one
CREATE CLUSTERED INDEX [_dta_index_Users_c_9_292912115__K1] ON [dbo].[Users]
(
[UserId] ASC
)WITH (SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF,
ONLINE = OFF) ON [PRIMARY]
UserId is the primary key of the table Users. Is this index better than the one already in the table:
ALTER TABLE [dbo].[Users] ADD CONSTRAINT [PK_Users] PRIMARY KEY NONCLUSTERED
(
[UserId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF,
IGNORE_DUP_KEY = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]

Yes a primary key is always an index.
If you don't have any other clustered index on the table, then it's easy: a clustered index makes a table faster, for every operation. YES! It does. See Kim Tripp's excellent The Clustered Index Debate continues for background info.
So really, every useful table (except for maybe staging tables for bulkload or another few rare cases) ought to have a clustered index. If you don't have one, it's quite obvious the DTA would recommend one, and put it on the Primary Key column(s) by default.

Every table needs a clustered index and a primary key. By default, the PK is clustered but it can be non-clustered if you want like you're done.
You have specified a non-clustered PK so the profiler suggests a clustered index...
Note: a table without a clustered index is called a "heap" because it's a pile of unstructured data...

It is essentially suggesting that you should make the primary key a clustered index rather than an unclustered one. In most cases, this would be a good thing to do.

It is better because it is clustered.

Related

How do I insert a new record to a table containing just an IDENTITY column?

I have a single-column table where the column is a primary key and clustered index. It is used on other tables to relate records together. It doesn't seem an Insert statement is the way to go, there's no other columns to populate. It's a bit cumbersome to SET IDENTITY_INSERT off and on, etc.
I just need to "increment" the primary key of the table to the next integer value.
I believe it's an easy problem to solve, but I'm at that stage of mental exhaustion where the wheel is still spinning but the hamster is dead.
Here is a script to recreate the table I'm working with.
CREATE TABLE [dbo].[PKOnly]
(
[Id] [BIGINT] IDENTITY(1,1) NOT NULL,
CONSTRAINT [PK_PKOnly]
PRIMARY KEY CLUSTERED ([Id] ASC)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,
IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY];
You can use DEFAULT VALUES:
INSERT dbo.PKOnly DEFAULT VALUES;
Example db<>fiddle
Note this will also work if you have other columns with defaults.

speed up long running query on huge tables

I am facing with problematic query on Azure SQL database, which I need to speed up.
This is my query:
SELECT
[Incidents].[Incident_Number],
[Incidents].[Incidentinteraction],
[Incidents].[Incidentid],
[Address].[Ads_Sk]
FROM
[schema1].[Address] AS Address --3529046 rows
JOIN
[schema2].[Incidents] AS Incidents --3268375 rows
ON Incidents.[Ads_Sk_Incidentaddress] = Address.[Ads_Sk]
Address table has 2 indexes:
ALTER TABLE [schema1].[ADDRESS]
ADD PRIMARY KEY CLUSTERED ([ADS_SK] ASC, [ISCURRENTRECORD] ASC, [RECORDSTARTDATE] ASC)
WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF) ON [PRIMARY]
and a non-clustered index:
CREATE NONCLUSTERED INDEX [nci_ADDRESS_ADS_CURRENT]
ON [PROMISE_CDW].[ADDRESS] ([ADS_SK] ASC, [ISCURRENTRECORD] ASC)
WITH (STATISTICS_NORECOMPUTE = OFF, DROP_EXISTING = OFF, ONLINE = OFF) ON [PRIMARY]
Incident table has also two indexes:
ALTER TABLE [schema2].[INCIDENTS]
ADD PRIMARY KEY CLUSTERED ([INCIDENTID] ASC, [ISCURRENTRECORD] ASC, [RECORDSTARTDATE] ASC)
WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF) ON [PRIMARY]
and
CREATE NONCLUSTERED INDEX [nci_ADDRESS_ADS_SK_INCIDENT_NUMBER]
ON [schema2].[INCIDENTS] ([ADS_SK_INCIDENTADDRESS] ASC, [INCIDENT_NUMBER] ASC)
INCLUDE ([INCIDENTID], [INCIDENTINTERACTION])
WITH (STATISTICS_NORECOMPUTE = OFF, DROP_EXISTING = OFF, ONLINE = OFF) ON [PRIMARY]
GO
I got my results after 22 seconds and this is unacceptable for business users.
How can I speed up this query?
Thank you in advance for any hint
That query doesn't need a join, all the fields you're selecting belong to the Incidents table.
You're only using the Address table to filter rows that don't have Incidents.[Ads_Sk_Incidentaddress] as part of Address.[Ads_Sk], which is something you can easily do in a where clause with an in.

SQL performance advice

I know that it can be a tricky question and that it highly depends on context.
I have a database with a table containing around 10 millions lines (each line contains 4 varchar).
There is an index non clustered on the field (a varchar) used for the where.
I'm a bit confused because when selecting a line using a where on the indexed columns, it takes around a second to end.
Any advices to improve this response time ?
Would an indexed clustered be a good solution here?
Here is the table definition :
CREATE TABLE [dbo].[MYTABLE](
[ID] [uniqueidentifier] NOT NULL DEFAULT (newid()),
[CreationDate] [datetime] NOT NULL DEFAULT (getdate()),
[UpdateDate] [datetime] NULL,
[FIELD1] [varchar](9) NOT NULL,
[FIELD2] [varchar](max) NOT NULL,
[FIELD3] [varchar](1) NULL,
[FIELD4] [varchar](4) NOT NULL,
CONSTRAINT [PK_MYTABLE] 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]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
Here is the index definition :
CREATE UNIQUE NONCLUSTERED INDEX [IX_FIELD1] ON [dbo].[MYTABLE]
(
[FIELD1] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
And here is the query I use (very basic) :
SELECT * FROM MYTABLE WHERE FIELD1 = 'DATA'
For this case, since you are selecting all columns (*), changing your nonclustered index to a clustered one will improve the time, since accessing additional columns (columns not included in the index, not ordered nor by INCLUDE) from a nonclustered index will need to retrieve another page with the actual data.
Since you can't have more than 1 clustered index by table, you will have to drop the existing one (the PRIMARY KEY in this case) and create it afterwards.
ALTER TABLE dbo.MYTABLE DROP [PK_MYTABLE] -- This might fail if you have foreign keys
ALTER TABLE dbo.MYTABLE ADD CONSTRAINT PK_MYTABLE PRIMARY KEY NONCLUSTERED (ID)
DROP INDEX [IX_FIELD1] ON [dbo].[MYTABLE]
CREATE CLUSTERED INDEX [IX_FIELD1] ON [dbo].[MYTABLE] (FIELD1)
Indexes access times might greatly vary depending on their fragmentation also (if you have many inserts, deletes or updates with values that aren't bigger or lower than the last/first one).
Also keep in mind that if you are doing another operation like joins, function calls or additional WHERE filters, the enging might decide not to use the indexes.
If you are certain that the column used in your WHERE clause is unique, you may create a UNIQUE CLUSTERED INDEX on that column.
If values in that column are not unique, you can implement COVERING INDEXES. For example, if you had this index:
CREATE NONCLUSTERED INDEX IX_Column4 ON MyTable(Column4)
INCLUDE (Column1, Column2);
When executing the following query:
SELECT Column1, Column2 FROM MyTable WHERE Column4 LIKE 'Something';
You would (most likely) be using the IX_Column4 index. But when executing something like:
SELECT Column1, Column2, Column3 FROM MyTable WHERE Column4 LIKE 'Something';
You will not be benefited from the advantages that this kind of index have to offer.
If rows in your table are regurlarly INSERTED, DELETED or UPDATED you should check for INDEX FRAGMENTATION and REBUILD or REORGANIZE them.
I would recommend the following articles in case you want to lear more about indexes:
Available index types, check out the guidelines offered for each kind of index.
SQL Server Index Design Guide
Hope it helps.

Composite key in where condition - SQL Server

I'm involved in some data cleaning activities. My table does not have any unique identifier. So I decided to take 3 columns and make the index like below:
ALTER TABLE [dbo].[ISFTX]
ADD CONSTRAINT ISFTX_UNQ UNIQUE (IDNO,ACCTNUM,PANNO)
After altering table, a part of my alter script looks like this:
CONSTRAINT [ISFTX_UNQ] UNIQUE NONCLUSTERED
(
[IDNO] ASC,
[ACCTNUM] ASC,
[PANNO] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF,
ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
I want to use the combination of 3 columns as ONE KEY and put it in where condition so that I can search for other column values in the same table using this where condition(ONE KEY). How can I do this?
I would prefer any example of "Where" condition and this will help? OR Please suggest me any better way of doing this? Thanks.

Clustered primary key and relations

I'm struggeling with the primary keys in my database:
As you can see I use a clustered index. When I try to insert something like:
I get exception that the primary key is duplicated, that is not what I expected. The combination of idQuestionaire and version needs to be unique so that my insert script will work.
I tried the following:
In the "Keys" folder of servey there are 4 keys(the primary, the foreign key from parkinglottype, survey$idQuestionnaire_UNIQUE and survey$version_UNIQUE)
After removing the UNIQUE keys the insert script works fine but my foreign key to surveyquestion does not work anymore...
This is the code of "survey$idQuestionnaire_UNIQUE":
ALTER TABLE [dbo].[survey] ADD CONSTRAINT [survey$idQuestionnaire_UNIQUE] UNIQUE NONCLUSTERED
(
[idQuestionnaire] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
GO
And here my primary key:
ALTER TABLE [dbo].[survey] ADD CONSTRAINT [PK_survey_idQuestionnaire] PRIMARY KEY CLUSTERED
(
[idQuestionnaire] ASC,
[version] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
GO
How can I make the clustered Primary Key unique with 2 column and still be able to use it as a foreign key?
If the primary key of "survey" is the two columns "idQuestionnaire" and "version", then adding a unique index to "idQuestionnaire" is a mistake. That column alone is not unique, as is obvious from both your primary key constraint and your INSERT statement.
SQL Server builds an index on the primary key. Additional indexes on primary key columns are usually not necessary.
Your foreign key constraint needs to reference the pair of columns, as ...(Survey_idQuestionnaire, Survey_version) references [dbo].[survey] (idQuestionnaire, version).

Resources