I'm trying to create a table with a unique clustered index on Azure Synapse Analytics
I've tried
CREATE TABLE [myschema].[test] (
ID1 int UNIQUE NOT ENFORCED,
ID2 int UNIQUE NOT ENFORCED,
message varchar(MAX)
)
WITH (
CLUSTERED INDEX (ID1, ID2)
)
and
CREATE TABLE [myschema].[test] (
ID1 int,
ID2 int,
message varchar(MAX),
CONSTRAINT test_unique UNIQUE(ID1,ID2) NOT ENFORCED
)
WITH (
CLUSTERED INDEX (ID1, ID2)
)
I know they're equivalent and both the times I'm getting this error
Error: Cannot use duplicate column names in statistics. Column name 'ID1' listed more than once.
we are aware of this issue and working on a resolution . You do have a workaround for this , please try this and it should help.
CREATE TABLE [test1] (
ID1 int UNIQUE NOT ENFORCED,
ID2 int UNIQUE NOT ENFORCED,
message varchar(MAX)
)
WITH (
HEAP
)
GO
CREATE CLUSTERED INDEX isTest ON [Test1](ID1,ID2)
In Synapse you can create ONLY ONE Clustered Index and on one column.
If you need to further improve performance then you need to create a Non-Clustered Index.
In your case the code will be:
CREATE TABLE [myschema].[test] (
ID1 int UNIQUE NOT ENFORCED,
ID2 int UNIQUE NOT ENFORCED,
message varchar(MAX)) WITH (
CLUSTERED INDEX (ID1)) --Only ID1 is used as clustered index
If you want to make queries work faster you can add Non-Clustered Index.
You can refer below links to know more:
https://www.techrepublic.com/article/index-on-multiple-columns-for-sql-performance/
https://learn.microsoft.com/en-us/azure/synapse-analytics/sql-data-warehouse/sql-data-warehouse-tables-index
Thanks :)
Related
I'm relatively new to using SQL and I am trying to implement clustered and non-clustered indexes on my database to improve performance.
Most of my tables use composite keys which include a unique ID relating to a customer (UserId), a field that talks about each instance of the customer buying something(ActId) and other fields such as RefId (Referrals) and EventId (Events).
My question is, when creating a clustered index, would I just use the fields I use to create the composite key as the fields to use in the index?
An example;
I have a table that is comprised of UserId, ActId, RefId which are all used to create the composite key amongst other fields for dates, descriptions etc.
Would I just create a clustered index as such?;
CREATE CLUSTERED INDEX C_U_table_name_UserId_ActId,RefId ON table_name(UserId ASC, ActID ASC, RefID ASC);
Tbl example;
UserId int
ActId int
RefId int
DateofPurchase datetime
TimeofPurchase varchar(5)
Description varchar(max)
ReasonPurchase varchar(max)
Can you create an index on a table variable in SQL Server 2000?
i.e.
DECLARE #TEMPTABLE TABLE (
[ID] [int] NOT NULL PRIMARY KEY
,[Name] [nvarchar] (255) COLLATE DATABASE_DEFAULT NULL
)
Can I create an index on Name?
The question is tagged SQL Server 2000 but for the benefit of people developing on the latest version I'll address that first.
SQL Server 2014
In addition to the methods of adding constraint based indexes discussed below SQL Server 2014 also allows non unique indexes to be specified directly with inline syntax on table variable declarations.
Example syntax for that is below.
/*SQL Server 2014+ compatible inline index syntax*/
DECLARE #T TABLE (
C1 INT INDEX IX1 CLUSTERED, /*Single column indexes can be declared next to the column*/
C2 INT INDEX IX2 NONCLUSTERED,
INDEX IX3 NONCLUSTERED(C1,C2) /*Example composite index*/
);
Filtered indexes and indexes with included columns can not currently be declared with this syntax however SQL Server 2016 relaxes this a bit further. From CTP 3.1 it is now possible to declare filtered indexes for table variables. By RTM it may be the case that included columns are also allowed but the current position is that they "will likely not make it into SQL16 due to resource constraints"
/*SQL Server 2016 allows filtered indexes*/
DECLARE #T TABLE
(
c1 INT NULL INDEX ix UNIQUE WHERE c1 IS NOT NULL /*Unique ignoring nulls*/
)
SQL Server 2000 - 2012
Can I create a index on Name?
Short answer: Yes.
DECLARE #TEMPTABLE TABLE (
[ID] [INT] NOT NULL PRIMARY KEY,
[Name] [NVARCHAR] (255) COLLATE DATABASE_DEFAULT NULL,
UNIQUE NONCLUSTERED ([Name], [ID])
)
A more detailed answer is below.
Traditional tables in SQL Server can either have a clustered index or are structured as heaps.
Clustered indexes can either be declared as unique to disallow duplicate key values or default to non unique. If not unique then SQL Server silently adds a uniqueifier to any duplicate keys to make them unique.
Non clustered indexes can also be explicitly declared as unique. Otherwise for the non unique case SQL Server adds the row locator (clustered index key or RID for a heap) to all index keys (not just duplicates) this again ensures they are unique.
In SQL Server 2000 - 2012 indexes on table variables can only be created implicitly by creating a UNIQUE or PRIMARY KEY constraint. The difference between these constraint types are that the primary key must be on non nullable column(s). The columns participating in a unique constraint may be nullable. (though SQL Server's implementation of unique constraints in the presence of NULLs is not per that specified in the SQL Standard). Also a table can only have one primary key but multiple unique constraints.
Both of these logical constraints are physically implemented with a unique index. If not explicitly specified otherwise the PRIMARY KEY will become the clustered index and unique constraints non clustered but this behavior can be overridden by specifying CLUSTERED or NONCLUSTERED explicitly with the constraint declaration (Example syntax)
DECLARE #T TABLE
(
A INT NULL UNIQUE CLUSTERED,
B INT NOT NULL PRIMARY KEY NONCLUSTERED
)
As a result of the above the following indexes can be implicitly created on table variables in SQL Server 2000 - 2012.
+-------------------------------------+-------------------------------------+
| Index Type | Can be created on a table variable? |
+-------------------------------------+-------------------------------------+
| Unique Clustered Index | Yes |
| Nonunique Clustered Index | |
| Unique NCI on a heap | Yes |
| Non Unique NCI on a heap | |
| Unique NCI on a clustered index | Yes |
| Non Unique NCI on a clustered index | Yes |
+-------------------------------------+-------------------------------------+
The last one requires a bit of explanation. In the table variable definition at the beginning of this answer the non unique non clustered index on Name is simulated by a unique index on Name,Id (recall that SQL Server would silently add the clustered index key to the non unique NCI key anyway).
A non unique clustered index can also be achieved by manually adding an IDENTITY column to act as a uniqueifier.
DECLARE #T TABLE
(
A INT NULL,
B INT NULL,
C INT NULL,
Uniqueifier INT NOT NULL IDENTITY(1,1),
UNIQUE CLUSTERED (A,Uniqueifier)
)
But this is not an accurate simulation of how a non unique clustered index would normally actually be implemented in SQL Server as this adds the "Uniqueifier" to all rows. Not just those that require it.
It should be understood that from a performance standpoint there are no differences between #temp tables and #temp tables that favor variables. They reside in the same place (tempdb) and are implemented the same way. All the differences appear in additional features. See this amazingly complete writeup: https://dba.stackexchange.com/questions/16385/whats-the-difference-between-a-temp-table-and-table-variable-in-sql-server/16386#16386
Although there are cases where a temp table can't be used such as in table or scalar functions, for most other cases prior to v2016 (where even filtered indexes can be added to a table variable) you can simply use a #temp table.
The drawback to using named indexes (or constraints) in tempdb is that the names can then clash. Not just theoretically with other procedures but often quite easily with other instances of the procedure itself which would try to put the same index on its copy of the #temp table.
To avoid name clashes, something like this usually works:
declare #cmd varchar(500)='CREATE NONCLUSTERED INDEX [ix_temp'+cast(newid() as varchar(40))+'] ON #temp (NonUniqueIndexNeeded);';
exec (#cmd);
This insures the name is always unique even between simultaneous executions of the same procedure.
If Table variable has large data, then instead of table variable(#table) create temp table (#table).table variable doesn't allow to create index after insert.
CREATE TABLE #Table(C1 int,
C2 NVarchar(100) , C3 varchar(100)
UNIQUE CLUSTERED (c1)
);
Create table with unique clustered index
Insert data into Temp "#Table" table
Create non clustered indexes.
CREATE NONCLUSTERED INDEX IX1 ON #Table (C2,C3);
Can you create an index on a table variable in SQL Server 2000?
i.e.
DECLARE #TEMPTABLE TABLE (
[ID] [int] NOT NULL PRIMARY KEY
,[Name] [nvarchar] (255) COLLATE DATABASE_DEFAULT NULL
)
Can I create an index on Name?
The question is tagged SQL Server 2000 but for the benefit of people developing on the latest version I'll address that first.
SQL Server 2014
In addition to the methods of adding constraint based indexes discussed below SQL Server 2014 also allows non unique indexes to be specified directly with inline syntax on table variable declarations.
Example syntax for that is below.
/*SQL Server 2014+ compatible inline index syntax*/
DECLARE #T TABLE (
C1 INT INDEX IX1 CLUSTERED, /*Single column indexes can be declared next to the column*/
C2 INT INDEX IX2 NONCLUSTERED,
INDEX IX3 NONCLUSTERED(C1,C2) /*Example composite index*/
);
Filtered indexes and indexes with included columns can not currently be declared with this syntax however SQL Server 2016 relaxes this a bit further. From CTP 3.1 it is now possible to declare filtered indexes for table variables. By RTM it may be the case that included columns are also allowed but the current position is that they "will likely not make it into SQL16 due to resource constraints"
/*SQL Server 2016 allows filtered indexes*/
DECLARE #T TABLE
(
c1 INT NULL INDEX ix UNIQUE WHERE c1 IS NOT NULL /*Unique ignoring nulls*/
)
SQL Server 2000 - 2012
Can I create a index on Name?
Short answer: Yes.
DECLARE #TEMPTABLE TABLE (
[ID] [INT] NOT NULL PRIMARY KEY,
[Name] [NVARCHAR] (255) COLLATE DATABASE_DEFAULT NULL,
UNIQUE NONCLUSTERED ([Name], [ID])
)
A more detailed answer is below.
Traditional tables in SQL Server can either have a clustered index or are structured as heaps.
Clustered indexes can either be declared as unique to disallow duplicate key values or default to non unique. If not unique then SQL Server silently adds a uniqueifier to any duplicate keys to make them unique.
Non clustered indexes can also be explicitly declared as unique. Otherwise for the non unique case SQL Server adds the row locator (clustered index key or RID for a heap) to all index keys (not just duplicates) this again ensures they are unique.
In SQL Server 2000 - 2012 indexes on table variables can only be created implicitly by creating a UNIQUE or PRIMARY KEY constraint. The difference between these constraint types are that the primary key must be on non nullable column(s). The columns participating in a unique constraint may be nullable. (though SQL Server's implementation of unique constraints in the presence of NULLs is not per that specified in the SQL Standard). Also a table can only have one primary key but multiple unique constraints.
Both of these logical constraints are physically implemented with a unique index. If not explicitly specified otherwise the PRIMARY KEY will become the clustered index and unique constraints non clustered but this behavior can be overridden by specifying CLUSTERED or NONCLUSTERED explicitly with the constraint declaration (Example syntax)
DECLARE #T TABLE
(
A INT NULL UNIQUE CLUSTERED,
B INT NOT NULL PRIMARY KEY NONCLUSTERED
)
As a result of the above the following indexes can be implicitly created on table variables in SQL Server 2000 - 2012.
+-------------------------------------+-------------------------------------+
| Index Type | Can be created on a table variable? |
+-------------------------------------+-------------------------------------+
| Unique Clustered Index | Yes |
| Nonunique Clustered Index | |
| Unique NCI on a heap | Yes |
| Non Unique NCI on a heap | |
| Unique NCI on a clustered index | Yes |
| Non Unique NCI on a clustered index | Yes |
+-------------------------------------+-------------------------------------+
The last one requires a bit of explanation. In the table variable definition at the beginning of this answer the non unique non clustered index on Name is simulated by a unique index on Name,Id (recall that SQL Server would silently add the clustered index key to the non unique NCI key anyway).
A non unique clustered index can also be achieved by manually adding an IDENTITY column to act as a uniqueifier.
DECLARE #T TABLE
(
A INT NULL,
B INT NULL,
C INT NULL,
Uniqueifier INT NOT NULL IDENTITY(1,1),
UNIQUE CLUSTERED (A,Uniqueifier)
)
But this is not an accurate simulation of how a non unique clustered index would normally actually be implemented in SQL Server as this adds the "Uniqueifier" to all rows. Not just those that require it.
It should be understood that from a performance standpoint there are no differences between #temp tables and #temp tables that favor variables. They reside in the same place (tempdb) and are implemented the same way. All the differences appear in additional features. See this amazingly complete writeup: https://dba.stackexchange.com/questions/16385/whats-the-difference-between-a-temp-table-and-table-variable-in-sql-server/16386#16386
Although there are cases where a temp table can't be used such as in table or scalar functions, for most other cases prior to v2016 (where even filtered indexes can be added to a table variable) you can simply use a #temp table.
The drawback to using named indexes (or constraints) in tempdb is that the names can then clash. Not just theoretically with other procedures but often quite easily with other instances of the procedure itself which would try to put the same index on its copy of the #temp table.
To avoid name clashes, something like this usually works:
declare #cmd varchar(500)='CREATE NONCLUSTERED INDEX [ix_temp'+cast(newid() as varchar(40))+'] ON #temp (NonUniqueIndexNeeded);';
exec (#cmd);
This insures the name is always unique even between simultaneous executions of the same procedure.
If Table variable has large data, then instead of table variable(#table) create temp table (#table).table variable doesn't allow to create index after insert.
CREATE TABLE #Table(C1 int,
C2 NVarchar(100) , C3 varchar(100)
UNIQUE CLUSTERED (c1)
);
Create table with unique clustered index
Insert data into Temp "#Table" table
Create non clustered indexes.
CREATE NONCLUSTERED INDEX IX1 ON #Table (C2,C3);
I wrote a script that creates some tables (it previously drops them if they exist) and then tries to create two indexes on each table.
The first index uses the Primary Key column to create a non-clustered index, and the second uses another column to create the clustered indexed. This is because the primary key column is a GUID instead of an int.
How can I drop the default index if I don't know it's name? or how can I specify a name for the primary key column index so I can drop it? Or better yet, how can I specify the 2 index i need right in the Create Table statement?
SELECT * FROM sys.indexes
However, I'm not understanding where in your process you actually have to drop an index.
You said you are creating some tables and then creating two indexes on each table.
If you are DROPping existing tables at the beginning, any indexes are automatically dropped.
There is no such thing as a default index.
Tables can either be heaps or clustered indexes. If you drop the clustered index, the table will be converted to a heap and any non-clustered indexes will have to be updated to point to the data in the unordered heap.
You can create like this all at once:
CREATE TABLE dbo.tbl
(
Id int NOT NULL IDENTITY (1, 1) CONSTRAINT UK_ID UNIQUE CLUSTERED,
SomeUUID UNIQUEIDENTIFIER NOT NULL CONSTRAINT PK_SomeUUID PRIMARY KEY NONCLUSTERED
)
Here's a SQLFiddle: http://sqlfiddle.com/#!6/d759e/12
You can define the two indices right after you create the table:
CREATE TABLE dbo.YourTable ( ...... )
GO
ALTER TABLE dbo.YourTable
ADD CONSTRAINT PK_YourTable PRIMARY KEY NONCLUSTERED (YourGuidColumn)
****************
this is crucial ! Otherwise, your PK will be clustered!
CREATE CLUSTERED INDEX IX01_YourTable ON dbo.YourTable(YourOtherColumn)
or even better:
CREATE UNIQUE CLUSTERED INDEX IX01_YourTable ON dbo.YourTable(YourOtherColumn)
That should create a non-clustered primary key and a separate (preferably unique) clustered index on a separate column.
I have a CustomerID column and an EffectiveDate column in a table.
I need the combination of these two to be unique.
However, I already have a primary key on an auto-numbered integer column.
What is a good way to accomplish my goal?
Thanks
Simply add a unique constraint:
Alter Table TableName
Add Constraint UC_TableName_Col1Col2 Unique ( Col1, Col2 )
SQL Server creates a unique index when you create a unique constraint. If there is already a clustered index, then the above will create that index as nonclustered. However, you can be explicit like so:
Alter Table TableName
Add Constraint UC_TableName_Col1Col2 Unique Nonclustered ( Col1, Col2 )
CREATE UNIQUE INDEX Some_Index_Name ON My_Table (CustomerID, EffectiveDate)
Try creating a UNIQUE index on the two columns.
CREATE TABLE Example
(Col1 int NOT NULL,
Col2 int NOT NULL,
UNIQUE (Col1, Col2)
)
Example taken from this thread.
CREATE TABLE MyTable
(
<columns here>
CONSTRAINT U_ConstraintName UNIQUE (CustomerID, EffectiveDate)
)