Does creation of a foreign key mean creation of an index? - sql

If I have a column a inside table Foo, and I create a new table Bar with a column b that is a foreign key to Foo.a, is column b automatically indexed for Bar, or must I still create an index on Bar.b if I want to efficiently search for all rows in Bar with b = 1?
(If it matters, I am using SQLite.)

Foreign keys are just used to 'force exists relationships between tables', but not automatically indexed based on their related column's index. Indexing Foo.a will speed up inserts/updates on Bar.b, while indexing Bar.b will speed up selects on Bar.b.

Creating a Foreign Key in SQLite is only creating a constraint. You should create the index yourself.
From the documentation, near the end of paragraph 3:
So, in most real systems, an index should be created on the child key
columns of each foreign key constraint.

You have to create the index yourself. At least I know no DBMS that does it automatically.

Related

HANA: How to add a unique contraint on a column that is already indexed?

Having the following schema:
CREATE TABLE test_table(
cryptid varchar(255)
);
CREATE INDEX cryptid_index ON test_table (cryptid);
I am trying to a unique contraint to the column.
ALTER TABLE test_table ADD constraint crypid_unique_contraint UNIQUE(cryptid);
But this runs into an error:
Could not execute 'ALTER TABLE test_table ADD constraint crypid_unique_contraint ...'
Error: (dberror) [261]: invalid index name: column list already indexed
I can understand that the column is already indexed because I have created the index by myself. But I want the column to be unique. Is there a way to do this?
This is indeed an undocumented limitation in the current HANA versions.
The only way to create a unique constraint on this column is to first drop the single-column index present on this column.
I would consider the fact that this is not documented a (docu-)bug. However, the fact that existing indexes cannot be generally reused for uniqueness checks is not.
Single-column indexes in HANA's column store (which is what you use by default) tables are not B-tree indexes. Instead, these are inverted indexes into the column store structure of the main store-part of a column store table column.
These inverted structures cannot be checked for duplicates in the current transactional context as easily as B-tree indexes could.
This, I believe, is the reason for
a) implementing the uniqueness check only on a specific index implementation in the column store,
and
b) making the system behavior (not allowing the "conversion" of an existing index into a unique index) consistent across all table types.
As a general comment: for column store tables the benefit of single-column indexes for lookup/point-read scenarios is very often not worth the additional storage & compute resource consumption. This type of index practically doubles the memory requirement for the indexed column. So the speed-up in looking up a specific value should be worthwhile this additional permanent resource consumption.
You may check the documentation on INDEXES system view. They listed this index types:
Type of row store indexes: BTREE, BTREE_UNIQUE, CPBTREE, and CPBTREE_UNIQUE.
"Simple" index and unique index are a different index types at a build time, so there's no way to change it after the index was declared.
In other databases when you add unique constraint, it creates a new unique index (like in T-SQL or MySQL or Postgers) or reuses current index with this column (as in Oracle). But HANA doesn't allow you to create ether additional index on the same column (due to unknown reason, I didn't find it documented) or enforce constraint using existing index (due to poor implementation of mixture of uniqueness and index type).
The only way to go is to drop existing index and create it as unique (it is equivalent to unique constraint from the metadata point of view) from scratch, which you cannot due to authorizations. Sad but...

Conditionally apply a unique index

I am implementing functionality for a table that when an edit/change is made it will save a copy of the pre-edit row and mark it as is_deleted=TRUE, this is inorder to create a history of changes made to a row.
The email column in the table has a unique index which is preventing this functionality from being successful.
PostgreSQL said: duplicate key value violates unique constraint "users_email_unique"
Detail: Key (email)=(TEST) already exists.
Is there a way to apply the unique index only to rows that are marked is_deleted=FALSE, thus allowing for the changes to occur.
Since version 7.2, you can use partial indexes in PostgreSql
Add a where clause to the create index statement to make it a partial index:
CREATE UNIQUE INDEX users_email_unique ON tests (email)
WHERE NOT is_deleted; -- assuming is_deleted is Boolean
Though PostgreSql supports Alter index, from what I understand from the documentation the alter is limited to either rename or setting the tablespace.
This means that you will need to drop and re-create the index in order to change it into a partial index:
DROP INDEX users_email_unique;
CREATE UNIQUE INDEX users_email_unique ON tests (email)
WHERE NOT is_deleted; -- assuming is_deleted is Boolean

Do I need to create indexes on foreign keys on Oracle?

I have a table A and a table B. A has a foreign key to B on B's primary key, B_ID.
For some reason (I know there are legitimate reasons) it is not using an index when I join these two tables on the key.
Do I need to separately create an index on A.B_ID or should the existence of a foreign key provide that?
The foreign key constraint alone does not provide the index on Oracle - one must (and should) be created.
Creating a foreign key does not automatically create an index on A.B_ID. So it would generally make sense from a query performance perspective to create a separate index on A.B_ID.
If you ever delete rows in B, you definitely want A.B_ID to be indexed. Otherwise, Oracle will have to do a full table scan on A every time you delete a row from B to make sure that there are no orphaned records (depending on the Oracle version, there may be additional locking implications as well, but those are diminished in more recent Oracle versions).
Just for more info: Oracle doesn't create an index automatically (as it does for unique constraints) because (a) it is not required to enforce the constraint, and (b) in some cases you don't need one.
Most of the time, however, you will want to create an index (in fact, in Oracle Apex there's a report of "unindexed foreign keys").
Whenever the application needs to be able to delete a row in the parent table, or update the PK value (which is rarer), the DML will suffer if no index exists, because it will have to lock the entire child table.
A case where I usually choose not to add an index is where the FK is to a "static data" table that defines the domain of a column (e.g. a table of status codes), where updates and deletes on the parent table are never done directly by the application. However, if adding an index on the column gives benefits to important queries in the application, then the index will still be a good idea.
SQL Server has never put indexes onto foreign key columns automatically - check out Kim Tripp's excellent blog post on the background and history of this urban myth.
It's usually a good idea to index your foreign key columns, however - so yes, I would recommend making sure each FK column is backed up by an index; not necessarily on that one column alone - maybe it can make sense to create an index on two or three columns with the FK column as the first one in there. Depends on your scenario and your data.
For performance reasons an index should be created. Is used in delete operations on primary table (to check that the record you are deleting is not used) and in joins that usually a foreign key is involved. Only few tables (I do not create them in logs) could be that do not need the index but probably, in this cases probably you don't need the foreign key constraint as well.
BUT
There are some databases that already automatically create indexes on foreign Keys.
Jet Engine (Microsoft Access Files)
Firebird
MySQL
FOR SURE
SQL Server
Oracle
DOES NOT
As with anything relating to performance, it depends on many factors and there is no silve bullet e.g. in a very high activilty environment the maintainance of an index may be unacceptable.
Most salient here would seem to be selectivity: if the values in the index would be highly duplicated then it may give better performance to drop the index (if possible) and allow a table scan.
UNIQUE, PRIMARY KEY, and FOREIGN KEY constraints generate indexes that enforce or "back" the constraint (and are sometimes called backing indexes). PRIMARY KEY constraints generate unique indexes. FOREIGN KEY constraints generate non-unique indexes. UNIQUE constraints generate unique indexes if all the columns are non-nullable, and they generate non-unique indexes if one or more columns are nullable. Therefore, if a column or set of columns has a UNIQUE, PRIMARY KEY, or FOREIGN KEY constraint on it, you do not need to create an index on those columns for performance.

Example Use of MySQL Indexes?

I was reading this question about the difference between these 4: Differences between INDEX, PRIMARY, UNIQUE, FULLTEXT in MySQL?
However, it is all very abstract and vague to me after reading it. Maybe it would help me understand it more concretely if I had some examples of when I would use it.
For example, I think for the field user_id, we would use the index UNIQUE, correct?
A primary key is not an index, per se --it's a constraint.
The primary key uniquely identifies a row from all the rest - that means the values must be unique. A primary key is typically made of one column, but can be made of more than one - multiple columns are called a composite....
A unique constraint is implemented in MySQL as an index - it guarantees that the same value can not occur more than once in the column(s) it is defined for. A unique constraint/index is redundant on a primary key column, and a primary key could be considered a synonym but with bigger implications. These too support composites...
In MySQL (and SQL Server), there are two types of indexes - clustered and non-clustered. A clustered index is typically associated with the primary key, and automatically created if a primary key is defined in the CREATE TABLE statement. But it doesn't have to be - it's the most important index to a table, so if it's more optimal to associate with different columns then the change should be reviewed. There can only be one clustered index for a table - the rest are non-clustered indexes. The amount of space you have to define indexes depends on the table engine - 1,000 for MyISAM and 767 for InnoDB. Indexes, clustered an non, are used to speed up data retrieval and their use can be triggered by using the columns in SELECT, JOIN, WHERE and ORDER BY clauses. But they also slow down INSERT/UPDATE/DELETE statements because of maintaining that data.
Full Text indexes are explicitly for Full Text Search (FTS) functionality - no other functionality can make use of them. They are only for columns defined with string based data types.
Mind that indexes are not ANSI - the similarities are thankfully relatively consistent. Oracle doesn't distinguish indexes - they're all the same.
Here's a brief description of what they are and when to use them:
INDEX: To speed up searches for values in this column.
UNIQUE: When you want to constrain the column to only contain unique values. This also adds an index. Example: if you only want each email to be registered once, you can add a unique constraint on the email column.
PRIMARY KEY: Contains the identity for each row. A primary key also implies a unique index and a "not null" constraint. It is often an auto-increment id, but it could also be a natural key. It is generally a good idea to create a primary key for each table, although it is not required.
FULL TEXT: This is a special type of index that allows you to perform searches for text strings much faster than LIKE '%foo%'.
Note that I am only considering single column indexes here. It is also possible to have a multi-column index.
if you have a "Person" table with id,name,email and bio information...
The primary key is the id, maybe it's a number it will allways be unique and you could use it as a reference in other tables (foreign keys)
the email is unique on each person, so you could add a UNIQUE constraint there
you might want to search a person over his name constantly so you could add an INDEX there
and finally a full text search in the bio attribute because it might be useful on a search
primary keys are also UNIQUE

Does creating a FK automatically index the column?

I am using mySQL 5.1 and am wondering, is it necessary to add CREATE INDEX syntax on a column after you have defined it in a FK relationship. Common sense tells me that if a column is a key (foreign or otherwise), then it needs to be indexed - but you never know ...
Do I have to EXPLICITLY create an index on my FK - or does creating an FK implicitly creates an index on the column ?
Quoting this page of the MySQL manual : 13.6.4.4. FOREIGN KEY Constraints :
InnoDB requires indexes on foreign
keys and referenced keys so that
foreign key checks can be fast and not
require a table scan. In the
referencing table, there must be an
index where the foreign key columns
are listed as the first columns in the
same order. Such an index is
created on the referencing table
automatically if it does not exist.