I have a request to replace the default clustered index with a non-primary attribute and I have an idea of how to simply drop an index and just make another one but I have no clue how to replace the default clustered index.
This is as far as I got.
CREATE INDEX newCustomerIndex ON CustomerInfo(fullname, homeAddress);
DROP INDEX CustomerInfo.PK__Customer__B611CB9D24135D51
However whenever I execute this piece of code I get this error
An explicit DROP INDEX is not allowed on index 'CustomerInfo.PK__Customer__B611CB9D24135D51'. It is being used for PRIMARY KEY constraint enforcement.
There are definitely times when you want the Clustered Index to be separate from the Primary Key - particularly when you search in 'ranges'.
For example, on log tables, I'll frequently have the primary key as an Identity (auto-incrementing) integer so each row is uniquely identified, but I'll put the clustered index on the date/time stamp field. This is because most of the reads etc will be within a date range and therefore the clustered index can be used directly. However, you cannot guarantee each date/time stamp is unique so you cannot use it as a primary key - and you can only have 1 clustered index on a table.
Note that the below is based on SQL Server - as per your tags. However, I'm not sure if the fields you are referring to are the current PK, or the ones you want to have as your clustered index. Therefore, I'll write this for a fictional table called 'dbo.Temp' with 'Auto_Id' and 'Log_datetime'.
I assume you already have the primary key which is also the clustered index. The typical process is as follows.
DROP and CREATE the current primary key, but as a non-clustered index rather than clustered
Create your new clustered index
However, you will also need a preceding and following step - identifying and managing the foreign key constraints. I'll get to this last.
To do step 1, I will usually open the table on the left (object explorer), open 'Indexes', then right-click on the index and script index -> 'DROP and CREATE to
This gives some code similar to the following
ALTER TABLE [dbo].[Temp] DROP CONSTRAINT [PK_Temp] WITH ( ONLINE = OFF )
GO
ALTER TABLE [dbo].[Temp] ADD CONSTRAINT [PK_Temp] PRIMARY KEY CLUSTERED
(
[Auto_ID] ASC
)
GO
I make one change to this before starting - change the new constraint to be NONCLUSTERED rather than clustered e.g.,
ALTER TABLE [dbo].[Temp] DROP CONSTRAINT [PK_Temp] WITH ( ONLINE = OFF )
GO
ALTER TABLE [dbo].[Temp] ADD CONSTRAINT [PK_Temp] PRIMARY KEY NONCLUSTERED -- modified here
(
[Auto_ID] ASC
)
GO
I then add my create index statement to create the index e.g.,
CREATE CLUSTERED INDEX CX_Temp ON dbo.Temp ([Log_Datetime], [Auto_ID])
GO
And then run.
Sometimes this won't work - especially when the index is being used for foreign key constraints (e.g., another table has a foreign link to this table/current PK) - therefore you cannot drop the PK, nor any of the following steps.
Therefore you need to find the relevant foreign key constraint. Once found (which can be annoying), I then usually do a similar thing to script the index deletion and re-creation (right-click on the foreign key, script it as 'DROP and CREATE to').
You then copy the first part (dropping the foreign key) before the script above, add the re-creating of the foreign key to the end. This therefore
disables the foreign key constraint
deletes/recreates the primary key as a non-clustered index
creates the new clustered index
recreates the foreign key constraint
Related
One can specify the index while creating the primary key:
CREATE TABLE t (a NUMBER, b NUMBER);
ALTER TABLE t ADD PRIMARY KEY (a,b) USING INDEX (CREATE INDEX i ON t(a,b));
This works for column subsets, too:
ALTER TABLE t ADD PRIMARY KEY (a) USING INDEX (CREATE INDEX i ON t(a,b));
I prefer unique indexes (because a non-unique index adds the rowid to each key which makes the index bigger and slightly slower). This works, too:
ALTER TABLE t ADD PRIMARY KEY (a,b) USING INDEX (CREATE UNIQUE INDEX i ON t(a,b));
However, subset and unique index results in an error:
ALTER TABLE t ADD PRIMARY KEY (a) USING INDEX (CREATE UNIQUE INDEX u ON t(a,b));
ORA-14196: Specified index cannot be used to enforce the constraint.
To summarize:
OK PRIMARY KEY (a,b) USING INDEX ( INDEX(a,b) )
OK PRIMARY KEY (a,b) USING INDEX ( UNIQUE INDEX(a,b) )
OK PRIMARY KEY (a) USING INDEX ( INDEX(a,b) )
ERROR PRIMARY KEY (a) USING INDEX ( UNIQUE INDEX(a,b) )
I completely fail to understand why that is not possible.
I need it quite often, for instance for tables with two primary key columns (say country, city) and one further column (say population). As I always query the further column, a three column index would make sense. As the first two columns are unique (per primary key), the index will be unique as well, but Oracle won't let me do this. Why?
This is a comment that doesn't fit in the comments section, and it may be blatantly wrong.
My take is that Oracle can enforce the uniqueness of primary keys using either 1) a unique index or 2) a non-unique index (functioanality that may exist for historical reasons). Therefore:
Case #1: if it uses a unique index, all the heavy lifting of finding out if a value is unique is done by the index itself. It's part of its features.
Case #2: if it uses a non-unique index, the index is used to store the values, but the uniqueness is validated by the primary key constraint itself that scans the index for multiple values.
Now, your four examples fall into:
case #1 (non-unique)
case #2 (unique)
case #1 (non-unique)
not case #1, not case #2. This is why I think Oracle does not allow this one.
And of course, if anyone knows better, please correct me.
the unique index on the column (a,b) cannot be used to enforce a primary key on the column (a) and the database has rigthly prevented you doing this action.
This is because (1,100),(1,101),(1,102) are are legitimate values in the unique index on (a,b) where are enforcing that column a contains only 1,2,3,...etc cannot be actioned using the same index.
I have a very large sales detail table in our DataWarehouse.
It has 5-7 nonclustered indexes, all partition aligned on date.
The clustered index is just on the date column.
I also have one nonclustered primary key set on an identity column.
If I want to do any form of partition swapping, I have to drop the primary key, then rebuild it when I am done.
Is there some other way to enforce the primary key while allowing me to swap partitions quickly? I want to swap out a partition to do processing on it, and this rebuild is unfortunately making that more time consuming then necessary.
I was considering adding saledate to the primary key, and then potentially making a unique constraint on the primary key column...but if I'm understanding correctly, a unique constraint just creates another nonclustered index that wouldn't be partition aligned.
Is there a solution to this, or do I have to suck it up and wait it out?
I am creating a table with following script (I used Using index).
CREATE TABLE TABLE1 (
C1 VARCHAR2(2 CHAR) NOT NULL ENABLE,
C2 VARCHAR2(1 CHAR) NOT NULL ENABLE,
CONSTRAINT TABLE_PK PRIMARY KEY (C1) USING INDEX TABLESPACE SFE_I1
)
TABLESPACE SFE_D1;
In the above query index will create for what column?
CREATE INDEX IDX_TABLE ON TABLE1 (C1) TABLESPACE SFE_I1;
If I am creating index with the above create index query, it will create index for C1 column. But what is the difference between to this two scripts.
As well if I run both this query, what should happen. And what is the suggested way to do this?
If my create table script contains composite primary key and i am using USING INDEX keyword then how index will be created (will it create a single index for all the composite columns)
The important part of the create table statement, for this question, is the CONSTRAINT TABLE_PK PRIMARY KEY (C1) USING INDEX TABLESPACE SFE_I1. Let's break it down and understand it:
CONSTRAINT TABLE_PK
You're creating a constraint named table_pk.
PRIMARY KEY
This constraint is a primary key
(C1)
On the column c1
USING INDEX TABLESPACE SFE_I1
A primary key, implicitly needs to create an index so it can efficiently search for duplicates that would violate the constraint. Like with explicitly created indexes (e.g., your second statement), the index would be created on the user's default tablespace, which isn't always the best idea. The using index tablespace syntax allows you do define which tablespace to use, in the same way you can use it when creating an index.
If you attempt to run both statements the second one should fail, since c1 is already indexed by the first one.
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.
In SQL Server 2005+ (I use both), does adding the UNIQUE constraint to a column automatically create an index, or should I still CREATE INDEX?
See this MSDN article:
The Database Engine automatically
creates a UNIQUE index to enforce the
uniqueness requirement of the UNIQUE
constraint.
If you do create an index, you'll end up with two indexes, as this example demonstrates:
create table TestTable (id int)
alter table TestTable add constraint unique_id unique (id)
create unique index ix_TestTable_id on TestTable (id)
select * from sys.indexes where [object_id] = object_id('TestTable')
This will display two unique indexes on TestTable; and the HEAP that represents the table itself.
Yes, it does.
In fact, you can even create a CLUSTERED UNIQUE CONSTRAINT:
ALTER TABLE mytable ADD CONSTRAINT UX_mytable_col1 UNIQUE CLUSTERED (col1)
, which will make the table to be clustered on col1.
Almost all databases create an index for UNIQUE CONSTRAINT, otherwise it would be very hard to maintain it.
Oracle doesn't even distinguish between UNIQUE CONSTRAINT and UNIQUE INDEX: one command is just a synonym for another.
The only difference in Oracle is that a UNIQUE INDEX should have a user-supplied name, while a UNIQUE CONSTRAINT may be created with a system-generated name:
ALTER TABLE mytable MODIFY col1 UNIQUE
This will create an index called SYS_CXXXXXX.
An index is created when you add a unique constraint:
Reference -- see the second paragraph.
When a UNIQUE constraint is added to
an existing column or columns in the
table, by default, the Database Engine
examines the existing data in the
columns to make sure all values are
unique. If a UNIQUE constraint is
added to a column that has duplicated
values, the Database Engine returns an
error and does not add the constraint.
The Database Engine automatically
creates a UNIQUE index to enforce the
uniqueness requirement of the UNIQUE
constraint. Therefore, if an attempt
to insert a duplicate row is made, the
Database Engine returns an error
message that states the UNIQUE
constraint has been violated and does
not add the row to the table. Unless a
clustered index is explicitly
specified, a unique, nonclustered
index is created by default to enforce
the UNIQUE constraint.