2010-03-12 198 views
2

運行以下SQL語句之後,您會看到,在第一個ALTER TABLE語句已運行後,MySQL自動爲tag_id列創建了非唯一索引question_tag_tag_id_tag_idMySQL忘記了爲外鍵自動創建索引?

第二ALTER TABLE語句運行後,我覺得MySQL也應該自動對我question_id列上創建一個非唯一索引question_tag_question_id_question_id

但是,從SHOW INDEXES語句輸出中可以看到,它不在那裏。

爲什麼MySQL忘記第二個ALTER TABLE聲明?

順便說一句,因爲我已經創建由question_idtag_id列使用的唯一索引question_id_tag_id_idx。爲每個人創建一個單獨的索引是多餘的?

mysql> DROP DATABASE mydatabase; 
Query OK, 1 row affected (0.00 sec) 

mysql> CREATE DATABASE mydatabase; 
Query OK, 1 row affected (0.00 sec) 

mysql> USE mydatabase; 
Database changed 
mysql> CREATE TABLE question (id BIGINT AUTO_INCREMENT, html TEXT, PRIMARY KEY(id)) ENGINE = INNODB; 
Query OK, 0 rows affected (0.05 sec) 

mysql> CREATE TABLE tag (id BIGINT AUTO_INCREMENT, name VARCHAR(10) NOT NULL, UNIQUE INDEX name_idx (name), PRIMARY KEY(id)) ENGINE = INNODB; 
Query OK, 0 rows affected (0.05 sec) 

mysql> CREATE TABLE question_tag (question_id BIGINT, tag_id BIGINT, UNIQUE INDEX question_id_tag_id_idx (question_id, tag_id), PRIMARY KEY(question_id, tag_id)) ENGINE = INNODB; 
Query OK, 0 rows affected (0.00 sec) 

mysql> ALTER TABLE question_tag ADD CONSTRAINT question_tag_tag_id_tag_id FOREIGN KEY (tag_id) REFERENCES tag(id); 
Query OK, 0 rows affected (0.10 sec) 
Records: 0 Duplicates: 0 Warnings: 0 

mysql> ALTER TABLE question_tag ADD CONSTRAINT question_tag_question_id_question_id FOREIGN KEY (question_id) REFERENCES question(id); 
Query OK, 0 rows affected (0.13 sec) 
Records: 0 Duplicates: 0 Warnings: 0 

mysql> SHOW INDEXES FROM question_tag; 
+--------------+------------+----------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+ 
| Table  | Non_unique | Key_name     | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | 
+--------------+------------+----------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+ 
| question_tag |   0 | PRIMARY     |   1 | question_id | A   |   0 |  NULL | NULL |  | BTREE  |   | 
| question_tag |   0 | PRIMARY     |   2 | tag_id  | A   |   0 |  NULL | NULL |  | BTREE  |   | 
| question_tag |   0 | question_id_tag_id_idx  |   1 | question_id | A   |   0 |  NULL | NULL |  | BTREE  |   | 
| question_tag |   0 | question_id_tag_id_idx  |   2 | tag_id  | A   |   0 |  NULL | NULL |  | BTREE  |   | 
| question_tag |   1 | question_tag_tag_id_tag_id |   1 | tag_id  | A   |   0 |  NULL | NULL |  | BTREE  |   | 
+--------------+------------+----------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+ 
5 rows in set (0.01 sec) 

mysql> 

回答

2

documentation

必須有在 外鍵列被列爲同一順序 第一列的索引。如果它不存在 ,則會自動在引用 表上創建索引 。

question_id是主鍵和question_id_tag_id_idx索引的第一列。因此,外鍵不需要進一步的索引。 question_id_tag_id_idx索引實際上是不必要的,因爲主鍵具有相同順序的相同列。主鍵是獨特的clustered indexes

對於question_tag_tag_id_tag_id外鍵,創建索引是因爲沒有以tag_id開頭的現有索引。

question_id_tag_id_idx索引(或主鍵)可用於外鍵上question_id,但不適合於tag_id外鍵是由部分中的文檔中說明上how MySQL uses indexes原因是:

如果表中有多列 索引,則優化程序可以使用 索引的任何最左邊的前綴來查找行 。例如,如果在(col1,col2, col3)上有一個 三列索引,則您在(col1),(col1,col2), 和(col1,col2,col3)上具有索引搜索 功能。

外鍵需要能夠快速查找引用表(question_tag)中的值。 question_id首先出現在question_id_tag_id_idx(是最左邊的前綴)中,因此可以使用此索引。 tag_id出現第二,所以索引不能使用。

+0

我明白了,這意味着我不必創建'question_id_tag_id_idx'索引,因爲'question_id'列是聚簇索引中最左邊的前綴模式之一,它已經可以用來查找' question_tag'表格由一個問題ID快速。但'tag_id'列沒有,這就是爲什麼它需要一個單獨的索引來快速查找'question_tag'表中的標籤ID。它是否正確? – bobo 2010-03-12 01:48:45

+0

@bobo'question_id_tag_id_idx'不需要,因爲它只是重複主鍵。 'tag_id'需要單獨的索引,因爲它不會出現在'question_id_tag_id_idx'索引或主鍵的開頭。 – 2010-03-12 10:04:49

1

在多列索引中,我相信您可以免費獲得第一列的索引,就像只有該列的索引一樣。

更新:只有在另一個回答者指出的特定索引中,非空並且成爲「聚簇索引」時纔是這種情況。

+0

感謝您的信息。 – bobo 2010-03-12 01:50:36