ChatGPT解决这个技术问题 Extra ChatGPT

Primary key or Unique index?

At work we have a big database with unique indexes instead of primary keys and all works fine.

I'm designing new database for a new project and I have a dilemma:

In DB theory, primary key is fundamental element, that's OK, but in REAL projects what are advantages and disadvantages of both?

What do you use in projects?

EDIT: ...and what about primary keys and replication on MS SQL server?

There are some additional considerations discussed here (albeit with the additional context of a covering index) - dba.stackexchange.com/questions/21554/…
NOTE: SQLite is different in that they do allow primary key to be null, against the common standard due to legacy issue. sqlite.org/lang_createtable.html

M
Mark Byers

What is a unique index?

A unique index on a column is an index on that column that also enforces the constraint that you cannot have two equal values in that column in two different rows. Example:

CREATE TABLE table1 (foo int, bar int);
CREATE UNIQUE INDEX ux_table1_foo ON table1(foo);  -- Create unique index on foo.

INSERT INTO table1 (foo, bar) VALUES (1, 2); -- OK
INSERT INTO table1 (foo, bar) VALUES (2, 2); -- OK
INSERT INTO table1 (foo, bar) VALUES (3, 1); -- OK
INSERT INTO table1 (foo, bar) VALUES (1, 4); -- Fails!

Duplicate entry '1' for key 'ux_table1_foo'

The last insert fails because it violates the unique index on column foo when it tries to insert the value 1 into this column for a second time.

In MySQL a unique constraint allows multiple NULLs.

It is possible to make a unique index on mutiple columns.

Primary key versus unique index

Things that are the same:

A primary key implies a unique index.

Things that are different:

A primary key also implies NOT NULL, but a unique index can be nullable.

There can be only one primary key, but there can be multiple unique indexes.

If there is no clustered index defined then the primary key will be the clustered index.


Note that A unique index is an index on a column is not entirely accurate as one unique index or primary key can include more than one column.
@Alexandre Jasmin: Fixed thanks. The part about multiple columns is mentioned later.
With reference to nulls, ansi standards allow multiple null values in an data set with a unique constraint on it, and that is also the implementation on Oracle and PostgreSQL. I believe that SQL Server only allows one null value though.
but still i did not get it, like when to use primary key or when to use unique index ? or may be both at the in same situations.
s
shiser

You can see it like this:

A Primary Key IS Unique

A Unique value doesn't have to be the Representaion of the Element

Meaning?; Well a primary key is used to identify the element, if you have a "Person" you would like to have a Personal Identification Number ( SSN or such ) which is Primary to your Person.

On the other hand, the person might have an e-mail which is unique, but doensn't identify the person.

I always have Primary Keys, even in relationship tables ( the mid-table / connection table ) I might have them. Why? Well I like to follow a standard when coding, if the "Person" has an identifier, the Car has an identifier, well, then the Person -> Car should have an identifier as well!


In your relationship tables: do you mean you introduce a new column with an artificial primary key (an integer for example) or do you use a composed primary key (person_id, car_id)?
primary key (person_id, car_id) would be the best. But i generally create a new column, sure it gives some overhead but i've concidered it being good. You never know if you want to relate to a specific relation in a later scenario.
The other thing the surrogate primary key does for your composite/join table is ease maintenance of manual tasks.
You only need a primary key if you're going to have children. Why add a column and a sequence if the value appears nowhere, if the value is used for nothing? It's make-work in order to stop Access from asking for a PK. Make a PK if you need to identify the record in a child, otherwise it's a waste.
If it has nothing to do with relations what does it have to do with? You point to a field and say, that's primary. And? Then what happens? And if there's no natural pk, I add a column and a sequence and a trigger and all because ____? Some just needs to be Primary. I eschew rules without reasons.
J
Jonas Lincoln

Foreign keys work with unique constraints as well as primary keys. From Books Online:

A FOREIGN KEY constraint does not have to be linked only to a PRIMARY KEY constraint in another table; it can also be defined to reference the columns of a UNIQUE constraint in another table

For transactional replication, you need the primary key. From Books Online:

Tables published for transactional replication must have a primary key. If a table is in a transactional replication publication, you cannot disable any indexes that are associated with primary key columns. These indexes are required by replication. To disable an index, you must first drop the table from the publication.

Both answers are for SQL Server 2005.


THAT scares the hell out of me (first quote). Why? I have a person table with an arbitrary ID that's my PK but I decide to add a UK to Phone, Email, & SSN... so now 4 different tables join to person on 4 different columns? I think I'd forgo any flexibility you might get for consistency.
a
aekeus

The choice of when to use a surrogate primary key as opposed to a natural key is tricky. Answers such as, always or never, are rarely useful. I find that it depends on the situation.

As an example, I have the following tables:

CREATE TABLE toll_booths (
    id            INTEGER       NOT NULL PRIMARY KEY,
    name          VARCHAR(255)  NOT NULL,
    ...
    UNIQUE(name)
)

CREATE TABLE cars (
    vin           VARCHAR(17)   NOT NULL PRIMARY KEY,
    license_plate VARCHAR(10)   NOT NULL,
    ...
    UNIQUE(license_plate)
)

CREATE TABLE drive_through (
    id            INTEGER       NOT NULL PRIMARY KEY,
    toll_booth_id INTEGER       NOT NULL REFERENCES toll_booths(id),
    vin           VARCHAR(17)   NOT NULL REFERENCES cars(vin),
    at            TIMESTAMP     DEFAULT CURRENT_TIMESTAMP NOT NULL,
    amount        NUMERIC(10,4) NOT NULL,
    ...
    UNIQUE(toll_booth_id, vin)
)

We have two entity tables (toll_booths and cars) and a transaction table (drive_through). The toll_booth table uses a surrogate key because it has no natural attribute that is not guaranteed to change (the name can easily be changed). The cars table uses a natural primary key because it has a non-changing unique identifier (vin). The drive_through transaction table uses a surrogate key for easy identification, but also has a unique constraint on the attributes that are guaranteed to be unique at the time the record is inserted.

http://database-programmer.blogspot.com has some great articles on this particular subject.


e
empi

There are no disadvantages of primary keys.

To add just some information to @MrWiggles and @Peter Parker answers, when table doesn't have primary key for example you won't be able to edit data in some applications (they will end up saying sth like cannot edit / delete data without primary key). Postgresql allows multiple NULL values to be in UNIQUE column, PRIMARY KEY doesn't allow NULLs. Also some ORM that generate code may have some problems with tables without primary keys.

UPDATE:

As far as I know it is not possible to replicate tables without primary keys in MSSQL, at least without problems (details).


There is overhead when new rows are inserted or that column is updated .
R
Ray Hidayat

If something is a primary key, depending on your DB engine, the entire table gets sorted by the primary key. This means that lookups are much faster on the primary key because it doesn't have to do any dereferencing as it has to do with any other kind of index. Besides that, it's just theory.


the table will ve sorted by the clustered index not neccesarily by the primary key.
it just so happens that most people set their primary key to be the clustered index.
Which we know is often a Really Bad Idea, unless we like hot-spots and unbalanced index trees in our tables, of course...
It's not ALWAYS a Really Bad Idea. Know your data, know your RDBMS, know what the choices mean. Rarely is choice ALWAYS good or bad. If was ALWAYS one, the database would mandate it or disallow it. They give you the choice because 'It Depends.'
t
tddmonkey

In addition to what the other answers have said, some databases and systems may require a primary to be present. One situation comes to mind; when using enterprise replication with Informix a PK must be present for a table to participate in replication.


P
Peter Parker

As long as you do not allow NULL for a value, they should be handled the same, but the value NULL is handled differently on databases(AFAIK MS-SQL do not allow more than one(1) NULL value, mySQL and Oracle allow this, if a column is UNIQUE) So you must define this column NOT NULL UNIQUE INDEX


MS-SQL does allow multiple NULL values in a column that has a unique index, as should every RDBMS. Think of it this way: NULL is not a value, so when you insert a second NULL, it will never match an existing one. The expression (NULL == NULL) does not evalute to true or false, it evaluates to NULL.
thanx gregmac, I was not sure, if MS follows this. I remembered some MS Quirks with this, however some years ago(pre 2000) and could also be an old access-DB cough
W
Walter Mitty

There is no such thing as a primary key in relational data theory, so your question has to be answered on the practical level.

Unique indexes are not part of the SQL standard. The particular implementation of a DBMS will determine what are the consequences of declaring a unique index.

In Oracle, declaring a primary key will result in a unique index being created on your behalf, so the question is almost moot. I can't tell you about other DBMS products.

I favor declaring a primary key. This has the effect of forbidding NULLs in the key column(s) as well as forbidding duplicates. I also favor declaring REFERENCES constraints to enforce entity integrity. In many cases, declaring an index on the coulmn(s) of a foreign key will speed up joins. This kind of index should in general not be unique.


A primary key in MS SQL Server always is both UNIQUE and NOT NULL - e.g. it's really just a Unique index, but with the added restriction that it cannot be NULL.
Oracle can enforce a Unique Constraint with a non-unique index. I'd be surprised if MSSS couldn't. Saying "it's really just a unique index" is a disservice.
"In many cases, declaring an index on the coulmn(s) of a foreign key will speed up joins." this is almost always not true in a data warehousing world where hash joins would be prefered if available.
The OP didn't mention warehouses. I'm not sure how hash loins work on sql server. How much of the work can be done at warehouse update time.
N
Nico Bester

There are some disadvantages of CLUSTERED INDEXES vs UNIQUE INDEXES.

As already stated, a CLUSTERED INDEX physically orders the data in the table.

This mean that when you have a lot if inserts or deletes on a table containing a clustered index, everytime (well, almost, depending on your fill factor) you change the data, the physical table needs to be updated to stay sorted.

In relative small tables, this is fine, but when getting to tables that have GB's worth of data, and insertrs/deletes affect the sorting, you will run into problems.


What's the advantage, then? sorted queries are faster? is this better for a use-case when you write most of your data once (or rarely) and query it all the time?
H
HLGEM

I almost never create a table without a numeric primary key. If there is also a natural key that should be unique, I also put a unique index on it. Joins are faster on integers than multicolumn natural keys, data only needs to change in one place (natural keys tend to need to be updated which is a bad thing when it is in primary key - foreign key relationships). If you are going to need replication use a GUID instead of an integer, but for the most part I prefer a key that is user readable especially if they need to see it to distinguish between John Smith and John Smith.

The few times I don't create a surrogate key are when I have a joining table that is involved in a many-to-many relationship. In this case I declare both fields as the primary key.


“I almost never create a table without a numeric primary key”: why always numeric? A primary key does not need to be numeric (neither it needs to be AUTO_INCREMENT by the way).
@Hinou57, because I have found that natural keys rarely actually are unique and that they are almost always changeable. Furthere joins on intergers are generally much faster than joins on varcahrr natural keys or worse composite keys. I would not use them nmost of the time. This may vary do to the type of information you store in your database, but in my personal experience I have found natural keys to be extremely unreliable over time.
Thanks for the reply HLGEM. What do you mean with unreliable? Performance? (I hope that's not a matter of reliability in the sense of data integrity). I'm a bit surprised by your words, as I though using integer keys or more natural keys like short VARCHAR, would likely makes just a tiny difference as hashing is used everywhere even with the most simple DB engines.
THey are unreliable in many cases becasue they aren't reliably unique even though they are supposed to be. They are unreliable becasue they change and that can affect millions of records in an uopdate. This is my experience having seen and managed or queried data from or imported data from hundreds of databases that store data about many differnt types of information.
H
Hibou57

My understanding is that a primary key and a unique index with a not‑null constraint, are the same (*); and I suppose one choose one or the other depending on what the specification explicitly states or implies (a matter of what you want to express and explicitly enforce). If it requires uniqueness and not‑null, then make it a primary key. If it just happens all parts of a unique index are not‑null without any requirement for that, then just make it a unique index.

The sole remaining difference is, you may have multiple not‑null unique indexes, while you can't have multiple primary keys.

(*) Excepting a practical difference: a primary key can be the default unique key for some operations, like defining a foreign key. Ex. if one define a foreign key referencing a table and does not provide the column name, if the referenced table has a primary key, then the primary key will be the referenced column. Otherwise, the the referenced column will have to be named explicitly.

Others here have mentioned DB replication, but I don't know about it.


C
Chirag

Unique Index can have one NULL value. It creates NON-CLUSTERED INDEX. Primary Key cannot contain NULL value. It creates CLUSTERED INDEX.


M
Markus

In MSSQL, Primary keys should be monotonically increasing for best performance on the clustered index. Therefore an integer with identity insert is better than any natural key that might not be monotonically increasing.


R
Rodney P. Barbati

If it were up to me...

You need to satisfy the requirements of the database and of your applications.

Adding an auto-incrementing integer or long id column to every table to serve as the primary key takes care of the database requirements.

You would then add at least one other unique index to the table for use by your application. This would be the index on employee_id, or account_id, or customer_id, etc. If possible, this index should not be a composite index.

I would favor indices on several fields individually over composite indices. The database will use the single field indices whenever the where clause includes those fields, but it will only use a composite when you provide the fields in exactly the correct order - meaning it can't use the second field in a composite index unless you provide both the first and second in your where clause.

I am all for using calculated or Function type indices - and would recommend using them over composite indices. It makes it very easy to use the function index by using the same function in your where clause.

This takes care of your application requirements.

It is highly likely that other non-primary indices are actually mappings of that indexes key value to a primary key value, not rowid()'s. This allows for physical sorting operations and deletes to occur without having to recreate these indices.