MySQL: Composite Index vs Multiple Indices (Leftmost Index Prefixes) - mysql

We have a table that is currently using a composite (i.e. multi-column) index.
Let's say
PRIMARY KEY(A, B)
Of course we can rapidly search based on A alone (Leftmost Index Prefix) and if we want to efficiently search based on B alone, we need to create a separate index for B.
My question is that if I am doing:
PRIMARY KEY (B)
is there any value in retaining
PRIMARY KEY (A,B)
In other words will there be any advantage retaining
PRIMARY KEY (A,B)
if I have
PRIMARY KEY (A)
and
PRIMARY KEY (B)

You are missing a key point about PRIMARY KEY -- it is by definition (at least in MySQL), UNIQUE. And do not have more columns than are needed to make the PK unique.
If B, aloneis unique, then havePRIMARY KEY(B)` without any other columns in the PK definition.
If A is also unique, then do
PRIMARY KEY(B),
UNIQUE(A)
or swap them.
For a longer discussion of creating indexes, see my cookbook.
If it takes both columns to be "unique", then you may need
PRIMARY KEY(A, B),
INDEX(B)
or
PRIMARY KEY(B, A),
INDEX(A)
Until you have the SELECTs, it is hard to know what indexes to create.

You can't have multiple primary keys, so I'm going to assume you're really asking about having an ordinary index.
If you have an index on (A, B), it will be used for queries that use both columns, like:
WHERE A = 1 AND B = 2
as well as queries that just use A:
WHERE A = 3
But if you have a query that just uses B, e.g.
WHERE B = 4
it will not be able to use the index at all. If you need to optimize these queries, you should also have an index on B. So you might have:
UNIQUE KEY (A, B)
INDEX (B)

Related

sql management studio [duplicate]

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?
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.
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!
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.
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.
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).
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.
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.
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
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.
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.
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.
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.
Unique Index can have one NULL value. It creates NON-CLUSTERED INDEX.
Primary Key cannot contain NULL value. It creates CLUSTERED INDEX.
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.
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.

Can I have too many columns in my composite primary key on one table

I have a table that uses 2 foreign key fields and a date field.
Is it common to have a table use 3 or more fields as a primary key? And are there any disadvantages to doing this?
--
My 3 tables are employees, training, and emp_training. The employees table holds employee data. Training table holds different training courses. And I am designing the emp_training table to be the fields EmployeeID (FK), TrainingID (FK), OnDate.
An employee can do multiple training courses, and can do the same training course multiple times. But they cannot to the same training course more than once on the same day.
Which is better to implement:
Option A - Make all 3 fields a primary key
Option B - Add an autonumber PK field, and use a query to find any potential duplicates.
I've created many tables before using 2 fields as a primary key, but never 3, so I'm curious if there is any disadvantage to proceeding with option A
It's worth to mention, that with SQL Server the PK by default is the one and only clustered key, but you are allowed to create a non-clustered PK as well.
You may define a new clustered index which is not the PK. "Primary Key" is just a name actually...
The most important question is: Which columns participate in a clustered key and (this is the very most important question): Do they have an implicit sorting? And (very important too): Are there many update operations which change the content of participating columns?
You must be aware, that a clustered key defines the physical order on your hard disc. In other words: The clustered key is the table itself. You can think of an index with all columns included. If your leading column (worst case) is a GUID, each insert to your table will not be in order. This leads to a 99.99% fragmentation.
If a clustered index is bound to the time of insert or a running number (best case), it will never go into fragmentation!
What makes things worse: If there is a clustered key (whether it's called PK or not), it will be used as lookup key for other indexes.
So: in many cases it is best to use a running number as clustered key and a non-clustered multi-column index which is much faster to re-build than as if it was the clustered one.
All indexes will profit from this!
My advise for you:
Option C: a running number as PK and additionally a unique multi-column-key to ensure data integrity. No need to use own logic here...
Yes, you can have a poor strategy for choosing too many columns for your composite Primary Key (PK) if a better strategy could be employeed for uniqueness via secondary indexes.
Remember that the PK is special. There is only 1 physical / clustered ordering of your data. Changes to the data via Inserts and Updates (and incumbent shuffling) has overhead there that would not exist if maintained in a secondary index.
So the following can have not-so-insignificant differences:
A primary key with 5 composite columns
vs.
A primary key with 1 or 2 columns plus
Secondary indexes that maintain uniqueness if thought through well
The former mandates movement of data between data pages to maintain the clustered index (the PK). Which might suggest why so often one sees:
(
id int auto_increment primary key,
...
)
in table designs.
Performance with Index Width:
The width of the PK in 1. above is narrow. The width of 2. can be quite wide. Wider keys propagating to child relationships will slow performance and concurrency.
Cases of FK compositions:
Special cases of compositions of foreign keys simply cannot be achieved without the use of a single column index, preferably the PK, as seen in this recent Answer of mine.
I dont think that there is any problem of creating a table with a composed PK ,such tables are needed in larger db .There is not a real problem in creating a table with 2FK whose with the OnDate field form the PK . Both ways are vailable.
Good luck!
If you assign primary key on more than one column it will be composite primary key. For example,
CREATE TABLE employee(
training VARCHAR(10),
emp_training VARCHAR (20),
OnDate INTEGER,
PRIMARY KEY (training, emp_training, OnDate)
)
there will be unique records in training, emp_training, OnDate together and can not be null together.
As already stated you can have a single primary key which consists of multiple columns.
If the question was how to make the columns primary keys separately, that's not possible. However, you can create 1 primary key and add two unique keys

MySQL InnoDB Primary Key with Many Columns

There is a table that contains more id data than real data data.
user_id int unsigned NOT NULL,
project_id int unsigned NOT NULL,
folder_id int unsigned NOT NULL,
file_id int unsigned NOT NULL,
data TEXT NOT NULL
The only way to create a unique primary key for this table would be a composite of (user_id, project_id, folder_id, file_id). I have frequently seen 2 column composite primary keys, but is it ok to have 4 or even more? According to MySQL: "All storage engines support at least 16 indexes per table and a total index length of at least 256 bytes. Most storage engines have higher limits.", so I know at least it is possible to do.
Past this, there are frequent queries to this table for various combinations of these ids. For example, find all projects for user X, find all files for user X, find all files for project Y and folder Z, etc. Should there be a separate individual index key on each of the id columns, or if there is a composite primary key that already contains all the columns does this make further individual keys redundant? There will be about 10 million - 50 million rows in the table at any time.
To summarize: is it ok to have a composite primary key with 4 (or more) id columns, and if there is a composite key does it make additional individual keys for each of those columns redundant?
Yes, it is ok to have a composite primary key with 4 or more columns.
It doesn't necessarily make additional keys for each of those columns redundant. For example, a key (a, b, c) will not be useful for a query SELECT ... WHERE b = 4. For that type of query you would rather have key (b) or key (b, c).
You need to examine your expected queries to determine which indexes you'll need. See this talk for more details: http://youtu.be/AVNjqgf7zNw
Yes this is OK if the data model supports it. You haven't shared much about your overall DB schema and how these items related to each other to determine if this might be considered the best approach. In other words is this truly the only way in which these for items are related to each other, or for example are the files REALLY related to projects and projects related to users or something like that such the splitting up these joins tables makes more logical sense.
If you are querying individual columns within this primary key, this might suggest to me that your schema is not quite correct. At a minimum you might need to add individual index on these columns to support such a query.
You're going to regret creating a compound primary key, it becomes really obnoxious to address individual rows and derivative indexes in MySQL must contain the primary key as a row identifier. You can create a UNIQUE that's compound, though.
You can have a composite key with a fairly large number of components, though keep in mind the more you add the bigger the index will get and the slower it will be to update when you do an INSERT. As your database grows in size, insert operations may get cripplingly slow.
This is why, whenever possible, you should try and minimize your index size.

Add two indexes to the same field in MySql

I have a table like this:
something
a [INT]
b [INT]
c [INT]
...where a, b and c are separate Foreign Keys pointing to three different table.id. Since I want to make all regs be unique, and after having read this great answer, I think I should create a new Index this way: UNIQUE INDEX(a, b, c) and (in my case) do IGNORE INSERTS.
But as you can see, I would have one KEY for each column and then another extra UNIQUE INDEX containing all three. Is this a normal thing? It seems strange to me, and I have never seen it.
It is perfectly normal and reasonable to include a column in more than one index. However, if the combination of (a, b, c) is enough to uniquely identify a row it seems that you want a PRIMARY index instead of a UNIQUE one here (technically there is very little difference, but semantically it might be the better choice).
Creating a Primary Key if Something (a, b, c) will invalidate the need for a unique index. An additional Unique index would make sense if your primary key was Something(a, b) and you wanted a Unique Index (a, b, c). But since all three columns are Foreignkey then a Primary key index is what you.

MySQL Innodb: Large Composite PK no other indexes

I am creating an Innodb table with four columns.
Table
column_a (tiny_int)
column_b (medium_int)
column_c (timestamp)
column_d (medium_int)
Primary Key -> column_a, column_b, column_c
From a logical standpoint, columns A, B, C must be made into a PK together.However, to increase performance and be able to read directly from the index (using index) I am considering a PK that comprises of all 4 columns (A, B, C, D).
QUESTION
What would the performance be of appending an additional column to the Primary Key on an Innodb table?
CONSIDERATIONS
Surrogate primary keys are absolutely out of the question
No other indexes will exist on this table
Table is read/write intensive (both about equal)
Thank you!
In InnoDB, the PRIMARY KEY index structure includes all non-key fields and will automatically use them for covering index queries and row elimination. There is no separate "data" structure other than the PRIMARY KEY index structure. It is not necessary to add additional fields to the PRIMARY KEY definition itself. Note that it won't show Using index when it's using the PRIMARY KEY on an InnoDB table, because it's a different code path which doesn't trigger the addition of that message.
A few things to consider:
Unless the query in question uses all of the columns in the index, the index will not be used.
As jeremycole notes: in the Innodb structure all row data is stored in the B-tree leaf nodes of the clustered index (PRIMARY INDEX)
This concept is covered:
http://www.innodb.com/wp/wp-content/uploads/2009/05/innodb-file-formats-and-source-code-structure.pdf
http://blog.johnjosephbachir.org/2006/10/22/everything-you-need-to-know-about-designing-mysql-innodb-primary-keys/
... and in jeremy's blog post here:
http://blog.jcole.us/2013/01/07/the-physical-structure-of-innodb-index-pages/
As such, a query on A, B, C will be sufficient for efficiently obtaining all values on this Innodb table.