2010-03-12 199 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