What is the best way to create an index as well as unique constraint on a schema like below?
Most of my queries will filter based on date column. If I create single column index on date and a unique constraint including both (date and key), I end up creating two indices as unique constraint also creates an index.
Is there a better way around this?
date
key
value
12-12-2021
a
3
12-12-2021
b
4
12-13-2021
a
3
12-13-2021
b
4
It depends.
Most of my queries will filter based on date column.
That's not enough information. For equality filters, a PRIMARY KEY on (date, key) (with date as leading column!) will typically do just fine:
CREATE TABLE tbl (
date date
, key text
, value int
, PRIMARY KEY (date, key)
);
Because ... see:
Is a composite index also good for queries on the first field?
PostgreSQL composite primary key
Why can I create a table with PRIMARY KEY on a nullable column?
How does PostgreSQL enforce the UNIQUE constraint / what type of index does it use?
This also covers range filters on date, but it's less than ideal when combined with an equality filter on key, because ... see:
Multicolumn index and performance
If your table is as simple as your example suggests and you typically include value in the SELECT list, consider a covering index (requires Postgres 11 or later) to get index-only scans:
...
, PRIMARY KEY (date, key) INCLUDE (value)
See:
Does a query with a primary key and foreign keys run faster than a query with just primary keys?
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 table with structure shown below :-
CREATE TABLE IF NOT EXISTS tblvideolikes (
itemid SERIAL PRIMARY KEY,
videoid integer NOT NULL,
userid integer NOT NULL,
CONSTRAINT liked_video_user UNIQUE(videoid,userid)
)
I have a lot of select queries with userid and videoid. I want to know whether adding unique constraint on both columns are sufficient or Do I need to do indexing on both of them as well. I have searched a lot about this but nothing makes it clear.
If you have to enforce the unique combination of both columns, you have to create the unique index on both of them.
Postgres will use that index as well if your where clause only has a condition on the first column of the index (the usual "it depends" on index usage still applies here).
Postgres is able to use a column that is not the leading column of an index for a where condition - however that is less efficient then using a leading column.
I would put that column first that is used more often as single where condition. The order of the columns does not matter for the uniqueness.
If the usage of (only) the second column is as frequent as using the (only) first column, then adding an additional index with only the second column could make sense, e.g.:
CREATE TABLE IF NOT EXISTS videolikes (
itemid SERIAL PRIMARY KEY,
videoid integer NOT NULL,
userid integer NOT NULL,
CONSTRAINT liked_video_user UNIQUE(videoid,userid)
);
create index on videolikes (userid);
The unique index would then be used for conditions on only videoid and (equality) conditions using both columns. The second index would be used for conditions on only the userid
Unrelated, but:
The itemid primary key is pretty much useless with the above setup. You needlessly increase the size of the table and add another index that needs to be maintained. You can simply leave it out and declare videoid, userid as the primary key:
CREATE TABLE IF NOT EXISTS videolikes (
videoid integer NOT NULL,
userid integer NOT NULL,
CONSTRAINT pk_videolikes primary key (videoid,userid)
);
create index on videolikes (userid);
Indexing on both the column separately is a better idea if you are going to do frequent queries from both sides.
I have a SQL server table on which I insert account wise data. Same account number should not be repeated on the same day but can be repeated if the date changes.
The customer retrieves the data based on the date and account number.
In short the date + account number is unique and should not be duplicate.
As both are different fields should I concatenate both and create a third field as primary key or there is option of having a primary key on the merge value.
Please guide with the optimum way.
You can create a composite primary key. When you create the table, you can do this sort of thing in SQL Server;
CREATE TABLE TableName (
Field1 varchar(20),
Field2 INT,
PRIMARY KEY (Field1, Field2))
Take a look at this question which helps with each flavour of SQL
How can I define a composite primary key in SQL?
PLEASE HAVE A LOOK, IT WILL CLEAR MOST OF THE DOUBTS !
We can state 2 or more columns combined as a primary key.
In that case every column included in primary key will be called : Composite Key
And mind you Composite keys can never be null !!
Now, first let me show you how to make 2 or more columns as primary key.
create table table_name ( col1 type, col2 type, primary key(col1, col2));
The benefit is :
col1 has value (X) and col2 has value (Y) then no other row can have col1 as (X) and col2 as (Y).
col1, col2 must have some values, they can't be null !!
HOPE THIS HELPS !
Not at all. Just use a primary key constraint:
alter table t add constraint pk_accountnumber_date primary key (accountnumber, date)
You can also include this in the create table statement.
I might suggest, however, that you use an auto-incrementing/identity/serial primary key -- a unique number for each row. Then declare the account number/date combination as a unique key. I prefer such synthetic primary keys for several reasons:
They make it easy to refer to a row in foreign key relationships.
They show the insert order into the table, so you can readily see the last inserted rows.
They make it simple to identify a single row for updates and deletes.
They hide the "id" information of the row from referring tables and applications.
The alternative is to have a PK which is an autoincrementing number and then put a unique unique index on the natural key. In this way uniqueness is preserved but you have the fastest possible joining to any child tables. If the table will not ever have child tables, the composite PK is a good idea. If there will be many child tables, this is could be a better choice.
Is there a difference between:
CREATE TABLE p(
product_no integer,
name text UNIQUE,
price numeric
);
and:
CREATE TABLE p(
product_no integer,
name text,
price numeric
);
CREATE UNIQUE INDEX customername
ON p
USING btree
(name COLLATE pg_catalog."default");
Will name be unique in both cases? What does it means when an index is unique?
EDIT: Postgres unique constraint vs index isn't answering my question. It considers a case with FK. My question has nothing to do with FK's. I just want to know if these two operations are equivalent in this example where no FK is involved.
Yes, there's a small difference. If you define a unique constraint it's visible in catalogs like information_schema. This is not true of a unique index.
Also, you can create things like partial unique indexes, but you cannot do that on a constraint.
Finally, unique constraints are SQL-standard.
A unique constraint implies the creation of a unique index, but not vice versa.
Use a unique constraint unless you have a good reason to create the unique index directly.
From documentation
Adding a unique constraint will automatically create a unique btree
index on the column or group of columns used in the constraint
So for your simplified example they are equivalent
I have to insert data into a table that has a PK in it. I also have another table that has a clustered index in it.
Should I drop the PK or the INDEX for the the best INSERT speeds? Then recreate them afterwards?
I load data to these types of tables on a routine basis and I want to make sure I am using the quickest way possible in all situations.
A primary key uniquely identifies a record and has other uses as well. An index makes select queries run faster.
You should never drop your primary key.
Whether or not you drop and re-create indexes when adding records depends on the circumstances.
Primary Key : Uniquely identifies the the data & we cannot insert duplicate Data.
Index : Index help us to get out data to us very quickly.
Very Important Concept about Primary key & Index
Suppose your column is marked with the primary key then Clustered Index automatically gets created,
If no clutstered index is already present in the table
To See that Your Index is Created Successfully, You can use.
sp_helpindex Index_Name
- About Index :
You cannot create a unique index on a single column if that column contains NULL in more than one row. Similarly, you cannot create a unique index on multiple columns if the combination of columns contains NULL in more than one row. These are treated as duplicate values for indexing purposes.
- About Primary Key :
All columns defined within a PRIMARY KEY constraint must be defined as NOT NULL. If nullability is not specified, all columns participating in a PRIMARY KEY constraint have their nullability set to NOT NULL.