2010-08-20 97 views
2

我有一個GUI工具創建一個數據庫,我發現這似乎是不一致的使用KEY(又名INDEX)定義:指標上主鍵和外鍵

CREATE TABLE `foo_bar` (
    `foo_id` int(10) unsigned NOT NULL, 
    `bar_id` int(10) unsigned NOT NULL, 
    PRIMARY KEY (`foo_id`, `bar_id`), 
    KEY `foo_bar_fk2` (`bar_id`), -- <== ??? 
    CONSTRAINT `foo_bar_fk1` FOREIGN KEY (`foo_id`) REFERENCES `foo` (`foo_id`) ON DELETE CASCADE ON UPDATE CASCADE, 
    CONSTRAINT `foo_bar_fk2` FOREIGN KEY (`bar_id`) REFERENCES `bar` (`bar_id`) ON DELETE CASCADE ON UPDATE CASCADE 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_spanish_ci COMMENT='Links between Foo and Bar'; 

我有以下幾個問題約指標

  1. 是否有必要明確定義索引主鍵和外鍵?
  2. 如果不是,你真的會得到兩個指數(和更少的性能)?
  3. InnoDB和MyISAM(外鍵除外)有什麼不同?

回答

4

我一直在做一些實驗上你告訴我,我還以爲我會分享它的答案。

首先,我創建一些測試表:

CREATE TABLE foo (
    foo_id int(10) unsigned NOT NULL, 
    PRIMARY KEY (foo_id) 
) 
ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_spanish_ci; 
CREATE TABLE bar (
    bar_id int(10) unsigned NOT NULL, 
    PRIMARY KEY (bar_id) 
) 
ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_spanish_ci; 


CREATE TABLE foo_bar (
    foo_id int(10) unsigned NOT NULL, 
    bar_id int(10) unsigned NOT NULL 
) 
ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_spanish_ci; 

到目前爲止,還沒有索引存在:

mysql> SHOW INDEXES FROM foo_bar; 
Empty set (0.00 sec) 

添加主鍵,生成索引:

mysql> ALTER TABLE foo_bar 
    -> ADD PRIMARY KEY (`foo_id`, `bar_id`); 
Query OK, 0 rows affected (0.70 sec) 
Records: 0 Duplicates: 0 Warnings: 0 

mysql> SHOW INDEXES FROM foo_bar; 
+---------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+ 
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | 
+---------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+ 
| foo_bar |   0 | PRIMARY |   1 | foo_id  | A   |   0 |  NULL | NULL |  | BTREE  |   | 
| foo_bar |   0 | PRIMARY |   2 | bar_id  | A   |   0 |  NULL | NULL |  | BTREE  |   | 
+---------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+ 
2 rows in set (0.02 sec) 

如果我添加一個外鍵在foo_id它重新使用主鍵索引,因爲該列是索引中的第一個:

mysql> ALTER TABLE foo_bar 
    -> ADD CONSTRAINT `foo_bar_fk1` FOREIGN KEY (`foo_id`) REFERENCES `foo` (`foo_id`) ON DELETE CASCADE ON UPDATE CASCADE; 
Query OK, 0 rows affected (0.27 sec) 
Records: 0 Duplicates: 0 Warnings: 0 

mysql> SHOW INDEXES FROM foo_bar; 
+---------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+ 
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | 
+---------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+ 
| foo_bar |   0 | PRIMARY |   1 | foo_id  | A   |   0 |  NULL | NULL |  | BTREE  |   | 
| foo_bar |   0 | PRIMARY |   2 | bar_id  | A   |   0 |  NULL | NULL |  | BTREE  |   | 
+---------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+ 
2 rows in set (0.00 sec) 

如果我添加上bar_id外鍵,它會創建一個索引,因爲沒有現成的指數可以重複使用:

mysql> ALTER TABLE foo_bar 
    -> ADD CONSTRAINT `foo_bar_fk2` FOREIGN KEY (`bar_id`) REFERENCES `bar` (`bar_id`) ON DELETE CASCADE ON UPDATE CASCADE; 
Query OK, 0 rows affected (0.25 sec) 
Records: 0 Duplicates: 0 Warnings: 0 

mysql> SHOW INDEXES FROM foo_bar; 
+---------+------------+-------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+ 
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | 
+---------+------------+-------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+ 
| foo_bar |   0 | PRIMARY  |   1 | foo_id  | A   |   0 |  NULL | NULL |  | BTREE  |   | 
| foo_bar |   0 | PRIMARY  |   2 | bar_id  | A   |   0 |  NULL | NULL |  | BTREE  |   | 
| foo_bar |   1 | foo_bar_fk2 |   1 | bar_id  | A   |   0 |  NULL | NULL |  | BTREE  |   | 
+---------+------------+-------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+ 
3 rows in set (0.02 sec) 

我們的一個外鍵的使用主鍵索引。這意味着我們不能刪除這樣的索引!

mysql> ALTER TABLE foo_bar 
    -> DROP PRIMARY KEY; 
ERROR 1025 (HY000): Error on rename of '.\test\#sql-568_c7d' to '.\test\foo_bar' (errno: 150) 

除非我們建立外鍵索引,或者我們刪除密鑰本身:

mysql> ALTER TABLE foo_bar 
    -> DROP FOREIGN KEY `foo_bar_fk1`; 
Query OK, 0 rows affected (0.19 sec) 
Records: 0 Duplicates: 0 Warnings: 0 

mysql> ALTER TABLE foo_bar 
    -> DROP PRIMARY KEY; 
Query OK, 0 rows affected (0.23 sec) 
Records: 0 Duplicates: 0 Warnings: 0 

的結論是MySQL的功能會在需要時,他們會自動創建索引(但只有在嚴格需要的情況下才可以)。

2

外鍵索引用於創建referential constraints

它們允許您定義級聯刪除子句,以便從父表中刪除行將從子表中刪除行。它也可以用來確保如果你試圖在子表中創建一行,它可以鏈接到父母(即Childrow.ParentId有效)

編輯:啊抱歉我誤解了。 InnoDB自動爲外鍵創建索引。請參閱does-mysql-index-foreign-key-columns-automatically

+0

對不起,如果我沒有正確解釋,我的問題是關於'KEY foo_bar_fk2(bar_id)'部分,即索引定義。主鍵和外鍵的用途很明確。 – 2010-08-20 08:19:50

+0

@Alvaro。對不起,我的誤解。回答編輯 – PaulG 2010-08-20 08:33:56

1

1)主鍵在mysql中自動編入索引。 2)參見上文,不必做 3)MyISAM不支持約束。 (我想你是暗示的,所以這對其他人來說更是如此)。當您嘗試在MyISAM中使用外鍵時,某些圖形工具(如MySQL Workbench)不會引發警報,但顯然不會創建它們。

順便說一句:你用什麼GUI(在哪個操作系統上)?

很好看的:d ata warehousing whitepaper(包含MyISAM和InnoDB表的比較)

+1

嗯...... 1)外鍵是否自動編入索引? 2)如果你這樣做,你會得到重複的索引嗎? 3)我在談論*索引* - 現在,我正在使用MySQL Workbench,HeidiSQL和文本編輯器的組合。 – 2010-08-20 08:31:01

+0

2)我從來沒有做過,只是試一試:)但要小心,你可以在你的GUI中完成它,但它永遠不會發生。 3)我也是,在MyISAM中沒有支持外鍵(約束)。我只是更明確地說出來,以防別人想知道。 – 2010-08-20 08:41:44

+0

我剛剛編輯我的帖子以添加一個鏈接,我一直在尋找自從我讀你的問題以來的所有時間。這有點過於矯枉過正,但這是一個很好的閱讀,並且在總覽表中有關於InnoDB和MyISAM的比較。只需在該頁面上下載.pdf白皮書即可。 HTH – 2010-08-20 08:48:26