I tried to create an index on MySQL using this query
CREATE TABLE test (id INT, age INT, INDEX(id,age));
DESCRIBE test; gives this:
+-------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------+------+-----+---------+-------+
| id | int(11) | YES | MUL | NULL | |
| age | int(11) | YES | | NULL | |
+-------+---------+------+-----+---------+-------+
When i tried to found why just the id was indexed i found 2 more things. That CREATE INDEX query requeires a name for the index and also that there is a USE INDEX () statement.
Now my questions:
Is the first query wrong or did I indexed both the id and the age like a pair and that's why just ID shows to be indexed?
Can I create indexes without providing a name, as I did in the first query (or when setting a column PRIMARY KEY)?
Should I add USE INDEX everytime I want to use the index? If yes, are there situations when the index is used by default (for example, when creating an index without a name, if possible)?
Your create table query with index - is ok, you can check it by running command
SHOW INDEX FROM test you'll see your index.
In general, it's good practice to create an index with own name (even you can omit it like in your query).
And USE INDEX - it's query performance optimization keyword which is just a suggestion which key mysql can use (you mush use it only if you clearly understand what are you doing, you must not use it for everyone query).
Use SHOW CREATE TABLE; it is more descriptive than DESCRIBE !
The DESCRIBE that you presented disagrees with the existence of INDEX(id,age).
Normally, id is the PRIMARY KEY of a table. You have broken with tradition; please explain what your intent is.
Do not use USE INDEX or FORCE INDEX -- it may help 'today', but is likely to hurt 'tomorrow'. Let the Optimizer decide which (if any) index to use.
We can't critique a schema without knowing what SELECTs you will be using against it.
Every table should have a PRIMARY KEY. Note: A PK is, by definition (in MySQL) both UNIQUE and INDEX.
There is almost no use for the name of an index. If you don't name an index, a name will be generated. A name is necessary when DROPping the index.
Related
Quite often I encounter situation like this:
table `user_adress`
+----------+-------------+--------------+---------+
|adress_id | user_id | adress_type |adress |
+----------+-------------+--------------+---------+
| 1 | 1 | home |adressXXX|
| 2 | 2 | home |adressXXX|
| 3 | 3 | home |adressXXX|
| 4 | 1 | work |adressXXX|
| 5 | 2 | work |adressXXX|
| 6 | 1 | second_home |adressXXX|
+----------+-------------+--------------+---------+
If I want to use it, I'm using queries like this:
SELECT `adress` FROM `user_adress` WHERE `user_id`=1;
Seems quite normal, but the thing is, that I use "useless" adress_id column, that has no other purpouse but to be an primary key with autoincrement just for the sake of having an primary key in MySQL table. I never use or need this number. So I figured out that I should not use primary key in my table at all, remove totally adress_id, and set INDEX (without unique) at user_id column. That seems to be good - or am I wrong?
I have some doubts, because as much as I'm reading, everywhere I see advices, that every table should, or even need to have primary key. But why? Perhaps my database is badly designed if I allowed this to happen, but looking on my extreamly simple example table - I can't imagine how this could be the case in every situation, especially in such simple cases. I deffinetly missunderstanded some simple, basic rules about creating tables and properly indexing them - where is the hole in my toughts?
Purely based on your table structure, I would say that your primary key is incorrect.
Instead, it looks like your primary should be:
PRIMARY KEY (user_id, address_type)
You are correct that every table should have a primary key ideally, but primary keys can be over multiple fields.
It is still sometimes easier to have a simple auto-incrementing id as your primary key. The Innodb storage engine will actually do this secretly in an invisible field.
Maybe in your limited example it's not needed, but in a lot of real-world cases it can just make it easier to work with the data. In that sense I would say that having an artificial auto-incrementing primary key is not a best practice from an academic standpoint, but it can be good idea from a 'real world, operational, and MySQL admin' perspective.
There's also ORM systems out there that simply require this (bad as that is).
As is evident in your data the primary key allow the access directly to a single row without any problem or ambiguity .. (expecially for delete or updated)
this is specifically the purpose of a primary key ..
di the fact you could need join this table to others table by user_id
and index (not unique ) on user_id
create index myidx on mytable(user_id)
is really useful for faster join allow a direct access only at the rows related to a single user_id
It's true that a relational database table needs a primary key.
But it all comes down to the definition of a primary key. A primary key is NOT necessarily a single integer column that auto-increments.
A primary key is any column or set of multiple columns that can uniquely identify every row. In your case, the combination of user_id and address_type can do this (as Evert posted already).
So if you make your table like this:
CREATE TABLE user_address (
user_id INT NOT NULL,
address_type varchar(10) NOT NULL,
address TEXT NOT NULL,
PRIMARY KEY (user_id, address_type)
);
Then you can update or delete one specific row at a time like this:
UPDATE user_address SET ...
WHERE user_id = ? AND address_type = ?;
Some people feel that it's more convenient to enforce a convention that every table should have a single integer column as its primary key. They even may insist that the column must be called id for the sake of consistency.
There's some advantage in consistency, but on the other hand, it's kind of brainless to insist on that convention even when it's not helpful.
I'm sure this is simple stuff to many of you, so I hope you can help easily.
If I have a MySQL table on the "many" side of a "one to many" relationship - like this:
Create Table MyTable(
ThisTableId int auto_increment not null,
ForeignKey int not null,
Information text
)
Since this table would always be used via a join using ForeignKey, it would seem useful to make ForeignKey a clustered index so that foreign keys would always be sorted adjacently for the same source record. However, ForeignKey is not unique, so I gather that it is either not possible or bad practice to make this a clustered index? If I try and make a composite primary key using (ForeignKey, ThisTableId) to achieve both the useful clustering and uniqueness, then there is an error "There can only be one auto column and it must be defined as a key".
I think perhaps I am approaching this incorrectly, in which case, what would be the best way to index the above table for maximum speed?
InnoDB requires that if you have an auto-increment column, it must be the first column in a key.
So you can't define the primary key as (ForeignKey, ThisTableId) -- if ThisTableId is auto-increment.
You could do it if ThisTableId were just a regular column (not auto-increment), but then you would be responsible for assigning a value that is at least unique among other rows with the same value in ForeignKey.
One method I have seen used is to make the column BIGINT UNSIGNED, and use a BEFORE INSERT trigger to assign the column a value from the function UUID_SHORT().
#ypercube correctly points out another solution: The InnoDB rule is that the auto-increment column should be the first column of some key, and if you create a normal secondary key, that's sufficient. This allows you to create a table like the following:
CREATE TABLE `MyTable` (
`ForeignKey` int(11) NOT NULL,
`ThisTableId` int(11) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`ForeignKey`,`ThisTableId`),
KEY (`ThisTableId`)
) ENGINE=InnoDB;
And the auto-increment works as expected:
mysql> INSERT INTO MyTable (ForeignKey) VALUES (123), (234), (345), (456);
mysql> select * from MyTable;
+------------+-------------+
| ForeignKey | ThisTableId |
+------------+-------------+
| 123 | 1 |
| 234 | 2 |
| 345 | 3 |
| 456 | 4 |
+------------+-------------+
I have 3 tables: users, pages and users_pages
Users Table
+----+------+-----
| id | name | ...
+----+------+-----
Pages Table
+----+------+-----
| id | name | ...
+----+------+-----
users_pages table, which says, which user is admin of which page.
+---------+---------+
| user_id | page_id |
+---------+---------+
| 1 | 1 | // means, user 1 is admin of page 1
+---------+---------+
in users_pages table, combination of user_id and page_id is a compound key ( primary key )
Is it possible to define user_id and page_id as foreign key while they both together are primary key?
Yes, Absolutely. You havn't mentioned which relational database you are using, but this is common practice, and allowable in all relational databases i know of.
My attempt at an additional explanation:-
Primary and foreign keys are more like 'theoretical' things rather than hard physical things. When looking at the nuts and bolts, I find it useful to think of only indexes and contraints, not of 'keys' as such
Thinking this way a 'primary key' is actually a combination of two separate things :-
A unique contraint. This checks for and refuses any attempts to
create duplicates.
An index based on the field. This just makes
it much faster to retrieve the record if you use that field to look
it up (select * from table where pkey = 'x')
A 'foreign key' in practice is just a contraint, not much different from the unique key contraint. It checks the records exist in the other table, and refuses any attempts to create records with no corresponding entries in the referred to table.
There is no reason why you cant have multiple contraints on the same field (that it is both unique and exists in another table), and whatever indexes is on the table in no way prevents you from adding any contraint you like. Therefore there is no problem having the same field as part of a primary key and it also have a foreign key contraint.
I'm making a table
Mobile Models Information
+-------------+-----------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+-----------------+------+-----+---------+----------------+
| ID | int(5) unsigned | NO | PRI | NULL | auto_increment |
| linktospecs | varchar(255) | YES | | NULL | |
| name | varchar(30) | NO | UNI | NULL | |
| company | varchar(20) | NO | | NULL | |
+-------------+-----------------+------+-----+---------+----------------+
4 rows in set (0.01 sec)
In this table, each mobile from any handset maker will appear only once, and with it, other information like its manufacturer's name and an official link to its specifications. That's all I can think of now.
What I want is, that since the name column would be inherently unique (two rows of same mobile models would be stupid), I want to be able to index using it, simply, because in my application, when a user searches for a mobile name, I would use the name column to retrieve all other columns from this table.
But in many examples I have seen people use an extra simple ID column that auto increments to keep it as a simple primary key.
So, my question is, do I need to keep the ID column or should the unique name column be sufficient to use this table?
I'm new to databases and SQL.
Having an ID column as the primary key is always a good idea because it will never change. If you need to change the name of a phone, and name is the primary key, then any previous references to that phone will immediately stop working because the primary key value is no longer there. On the other hand, if you have a unique ID for each one, you can change the name without affecting the ID, and all previous references will remain valid.
It's also possible that two different companies may come out with phones with the same name, in which case if name were your primary key then you would only be able to store information on one of them.
The primary key means that it will be a clustered index - you'll be searching for your name column more than you would be the id column so searches should improve minutely over a non-clustered index. -- https://stackoverflow.com/a/3543719/2724079
I would prefer ID, because name may match like Nokia 500 and HTC 500. You may not add company name in model name. In thise cases you may get multiple. Its better to use "ID" as key in this scenario.
If you prefer not using ID as a additional column then go with combination of company and name as key.
In my opinion using ID column would be better, as if in near by future if you want to add some functionality which includes foreign Key( primary key of a table that appears in other table) concept then Using ID may simply your task and also your effort in various aspect
(If you need to change the name of a phone, and name is the primary key, then any previous references to that phone will immediately stop working because the primary key value is no longer there)
I have a log table like this that saves all logs for all of my table in my MySQL database:
+-------+-----------+-------------+-------------+-----------+--------+
| LogID | LogTypeID | LogDateTime | ReferenceID | TableName | UserID |
+-------+-----------+-------------+-------------+-----------+--------+
| 1 | 1 | 2012-10... | 1 | client | 1 |
| 2 | 1 | 2012-10... | 1 | plan | 1 |
| ... | ... | ... | ... | ... | ... |
+-------+-----------+-------------+-------------+-----------+--------+
The log table saves all the logs when I Insert, Update, or Delete to my tables in my database which is identified by my LogTypeID column. The ReferenceID column is the Primary Key of the table identified in my TableName column, all my Primay Keys has the same type of int(10) and it is same for the ReferenceID column.
I always use my log table for identifying when this data was inserted so I cannot clear the logs.
I have no problem on it at first, but now my queries are becoming slow when using the log table because of many data. I try to improve the performance of my database server and it become a little faster than before, but still it is slow. Most of my queries INNER JOIN to the log table.
I was thinking of adding a Foreign Key to my ReferenceID to all the tables that uses the log table because I think Keys may improve the performance of my queries, but I'm not sure if it is feasible.
Can I make my ReferenceID column a foreign key to all my tables?
My database server is MySQL Server 5.5.25, my tables are all InnoDB.
Please help, thanks in advance.
If I understand correctly and ReferenceID holds different table PRIMARY KEY values, you will not be able to define it as a FOREIGN KEY, since a FOREIGN KEY constraint is only able to reference a single table and cannot switch based on other column values.
Instead, you can create an index on each of ReferenceID and TableName, or perhaps even a composite index across both of them:
CREATE INDEX `idx_referenceid` ON `log` (`ReferenceID`);
CREATE INDEX `idx_tablename` ON `log` (`TableName`);
Or as a composite index across both columns, assuming you always need both to query against log.
CREATE INDEX `idx_referenceid_tablename` ON `log` (`ReferenceID`,`TableName`);