復合主鍵
其實“主鍵是唯一的索引”這話有點歧義的。舉個例子,我們在表中創建了一個ID字段,自動增長,並設為主鍵,這個是沒有問題的,因為“主鍵是唯一的索引”,ID自動增長保證了唯一性,所以可以。
此時,我們再創建一個字段name,類型為varchar,也設置為主鍵,你會發現,在表的多行中你是可以填寫相同的name值的,這豈不是有違“主鍵是唯一的索引”這句話么?
所以我才說“主鍵是唯一的索引”是有歧義的。(復合主鍵)應該是“當表中只有一個主鍵時,它是唯一的索引;當表中有多個主鍵時,稱為復合主鍵,復合主鍵聯合保證唯一索引”。
為什么自增長ID已經可以作為唯一標識的主鍵,為啥還需要復合主鍵呢。因為,並不是所有的表都要有ID這個字段啊哈哈,比如,我們建一個學生表,沒有唯一能標識學生的ID,怎么辦呢,學生的名字、年齡、班級都可能重復,無法使用單個字段來唯一標識,這時,我們可以將多個字段設置為主鍵,形成復合主鍵,這多個字段聯合標識唯一性,其中,某幾個主鍵字段值出現重復是沒有問題的,只要不是有多條記錄的所有主鍵值完全一樣,就不算重復。
什么是數據表的復合主鍵
所謂的復合主鍵 就是指你表的主鍵含有一個以上的字段組成
比如
create table test
(
name varchar(19),
id number,
value varchar(10),
primary key (name,id)
)
上面的name和id字段組合起來就是你test表的復合主鍵
它的出現是因為你的name字段可能會出現重名,所以要加上ID字段這樣就可以保證你記錄的唯一性
一般情況下,主鍵的字段長度和字段數目要越少越好
聯合主鍵
什么是聯合主鍵?
(主鍵原則上是唯一的,別被唯一值所困擾。)
顧名思義就是多個主鍵聯合形成一個主鍵組合
一個簡單的例子
主鍵A跟主鍵B組成聯合主鍵
主鍵A跟主鍵B的數據可以完全相同(困擾吧,沒關系),聯合就在於主鍵A跟主鍵B形成的聯合主鍵是唯一的。
下例主鍵A數據是1,主鍵B數據也是1,聯合主鍵其實是11,這個11是唯一值,絕對不充許再出現11這個唯一值。(這就是多對多關系)
主鍵A數據主鍵B數據
1 1
2 2
3 3
主鍵A與主鍵B的聯合主鍵值最多也就是
11
12
13
21
22
23
31
32
33
聯合索引
顧名思義,就是幾個字段聯合起來,一起做的索引,為了講述,首先先建立一個表,test_union:
create table test_union ( id int auto_increment comment 'zhujian' primary key, k1 int not null comment 'lianheziduan1', k2 int not null comment 'lianheziduan2', k3 int not null comment 'lianheziduan3', k4 int not null comment 'lianheziduan4', k5 int not null comment 'lianheziduan5', k6 int null comment 'ziduan1', k7 int null comment 'ziduan2' ) ; create index test_union_k1_k2_k3_k4_k5_index on test_union (k1, k2, k3, k4, k5) ;
插入幾條數據:
insert into test_union(k1,k2,k3,k4,k5,k6,k7) values(1,1,1,1,1,1,1); insert into test_union(k1,k2,k3,k4,k5,k6,k7) values(2,2,2,2,2,2,2); insert into test_union(k1,k2,k3,k4,k5,k6,k7) values(3,3,3,3,3,3,3);
從如下幾條SQL語句講述聯合索引的使用:
EXPLAIN SELECT * FROM test_union where k1= 1; EXPLAIN SELECT * FROM test_union where k1= 1 AND k2 =1; EXPLAIN SELECT * FROM test_union where k1= 1 AND k3 = 1; EXPLAIN SELECT * FROM test_union where k1= 1 AND k4 =1; EXPLAIN SELECT * FROM test_union where k2= 1; EXPLAIN SELECT * FROM test_union where k6 = 1;
先看看每條語句的explain分析。
EXPLAIN SELECT * FROM test_union where k1= 1;
id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
---|---|---|---|---|---|---|---|---|---|
1 | SIMPLE | test_union | ref | test_union_k1_k2_k3_k4_k5_index | test_union_k1_k2_k3_k4_k5_index | 4 | const | 1 |
用到了聯合索引test_union_k1_k2_k3_k4_k5_index
,但是並沒有用到全部,之用到了聯合索引中的字段k1,也就是只有一個字段,所以key_len
的長度為4。
EXPLAIN SELECT * FROM test_union where k1= 1 AND k2 =1;
id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
---|---|---|---|---|---|---|---|---|---|
1 | SIMPLE | test_union | ref | test_union_k1_k2_k3_k4_k5_index | test_union_k1_k2_k3_k4_k5_index | 8 | const,const | 1 |
用到了聯合索引test_union_k1_k2_k3_k4_k5_index
,但是並沒有用到全部,之用到了聯合索引中的字段k1,k2,也就是只有兩個字段,所以key_len
的長度為8。
EXPLAIN SELECT * FROM test_union where k1= 1 AND k3 = 1;
id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
---|---|---|---|---|---|---|---|---|---|
1 | SIMPLE | test_union | ref | test_union_k1_k2_k3_k4_k5_index | test_union_k1_k2_k3_k4_k5_index | 4 | const | 1 |
用到了聯合索引test_union_k1_k2_k3_k4_k5_index
,但是並沒有用到全部,由於key_len
為4,可知之用到聯合索引的其中一位,那就是k1,但是k3也是聯合索引test_union_k1_k2_k3_k4_k5_index
的字段之一,這里沒有用的原因是,對於聯合索引來說,開始只有第一個字段的索引可用,當使用了第一個字段后,第二個字段的索引才有效,以此類推,這里的原因,筆者個人的理解如下,舉個簡單的例子,一共有四條數據{(1,1),(1,2),(2,1),(2,2)},這四條數據的是按照字典序排列,但是如果沒有使用第一個字段,直接使用第二個字段,對應的是{1,2,1,2},並不是排序好的,索引是無法建立的,不知道這樣理解是否有些不妥,就是索引需要一次使用,不能隔着字段使用。該例中由於k1是第一個字段,索引是建立好的,可以直接使用,這時k2的索引是可以使用的,但是由於沒有使用k2直接使用k3字段查詢,k3的字段索引不能使用,因此只能使用k1一個字段的索引,所以key_len
為4,而另一個字段k3查詢走的是where條件,所以字段Extra為Using where。
EXPLAIN SELECT * FROM test_union where k1= 1 AND k4 =1;
id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
---|---|---|---|---|---|---|---|---|---|
1 | SIMPLE | test_union | ref | test_union_k1_k2_k3_k4_k5_index | test_union_k1_k2_k3_k4_k5_index | 4 | const | 1 |
該例和上一條示例類似,由於未使用k2和k3,所以不能直接使用索引的k4字段,而另一個字段k4查詢走的是where條件,所以字段Extra為Using where。
注意: 以上幾條都用到了聯合索引,但都不是用到所有字段,記得之前接觸過一個詞叫”部分索引”,大概就是這個意思了吧!請大牛指正(zgsoft_happy@126.com)
EXPLAIN SELECT * FROM test_union WHERE k1 = 1 AND k2 = 1 AND k3 = 1 AND k4 = 1 AND k5 = 1;
id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
---|---|---|---|---|---|---|---|---|---|
1 | SIMPLE | test_union | ref | test_union_k1_k2_k3_k4_k5_index | test_union_k1_k2_k3_k4_k5_index | 20 | const,const,const,const,const | 1 |
該例使用了聯合索引的所有字段,一共是5個字段,因此key_len為20。
EXPLAIN SELECT * FROM test_union where k2= 1;
id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
---|---|---|---|---|---|---|---|---|---|
1 | SIMPLE | test_union | ALL | <null> | <null> | <null> | <null> | 3 | Using where |
這個例子的原理類似前面兩個部門索引的例子,由於沒有使用聯合索引的字段k1,直接使用k2,這個時候k2沒有索引。所以不能使用索引,而該表中又沒有其他包含k2的索引,因此沒有使用索引,直接遍歷所有的數據記錄查詢的,使用的是Using where。
EXPLAIN SELECT * FROM test_union where k6 = 1;
id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
---|---|---|---|---|---|---|---|---|---|
1 | SIMPLE | test_union | ALL | <null> | <null> | <null> | <null> | 3 | Using where |
這個好理解,因為k6字段沒有在任何索引里,所以不能使用索引,因此是直接遍歷所有的數據記錄查詢的,使用的是Using where。
至此,mysql的聯合索引的使用介紹完畢