Mysql索引與鍵

0.主鍵與索引的不同

主鍵在物理層面上只有兩個用途: 惟一地標識一行;作爲一個可以被外鍵有效引用的對象。 

索引是一種特殊的文件(InnoDB數據表上的索引是表空間的一個組成部分),它們包含着對數據表裏所有記錄的引用指針。下面是主鍵和索引的一些區別與聯繫。 

1. 主鍵一定是唯一性索引,唯一性索引並不一定就是主鍵。

2. 一個表中可以有多個唯一性索引,但只能有一個主鍵。

3. 主鍵列不允許空值,而唯一性索引列允許空值。 

4. 索引可以提高查詢的速度,不會約束字段的唯一非空性;而鍵主要約束記錄的唯一非空性。   

5. 不管是主鍵還是外鍵都必須建立在索引字段上

一、索引

http://blog.csdn.net/xluren/article/details/32746183

索引是對整張表的統計,可以提高查詢效率;但可能降低增刪改的效率;索引是用來查找記錄的,而鍵是用來約束記錄的。當然unique也對記錄有一定的約束作用。

1.索引帶來的查詢效率

如果正確合理設計並且使用索引的MySQL是一輛蘭博基尼的話,那麼沒有設計和使用索引的MySQL就是一個人力三輪車。對於沒有索引的表,單表查詢可能幾十萬數據就是瓶頸,而通常大型網站單日就可能會產生幾十萬甚至幾百萬的數據,沒有索引查詢會變的非常緩慢。還是以WordPress來說,其多個數據表都會對經常被查詢的字段添加索引。建立了索引的表只能在where後使用了該索引才能提高效率。

2.索引定義

索引是一種特殊的文件(InnoDB數據表上的索引是表空間的一個組成部分),它們包含着對數據表裏所有記錄的引用指針。更通俗的說,數據庫索引好比是一本書前面的目錄,能加快數據庫的查詢速度。數據庫查索引遠比直接查數據表(遍歷整個表)快。

索引分爲聚簇索引和非聚簇索引兩種,聚簇索引是按照數據存放的物理位置爲順序的,而非聚簇索引就不一樣了;聚簇索引能提高多行檢索的速度,而非聚簇索引對於單行的檢索很快。

3.索引的種類

a.普通索引INDEX

這是最基本的索引,它沒有任何限制,比如上文中爲title字段創建的索引就是一個普通索引,MyIASM中默認的BTREE類型的索引,也是我們大多數情況下用到的索引。

CREATE INDEX index_name ON table(column(length))

DROP INDEX index_name ON table

b.唯一索引UNIQUE

與普通索引類似,不同的就是:索引列的值必須唯一,但允許有空值(注意和主鍵不同)。如果是組合索引,則列值的組合必須唯一,創建方法和普通索引類似。

CREATE UNIQUE INDEX indexName ON table(column(length))

c.全文索引(FULLTEXT)

MySQL從3.23.23版開始支持全文索引和全文檢索,FULLTEXT索引僅可用於 MyISAM 表;不過切記對於大容量的數據表,生成全文索引是一個非常消耗時間非常消耗硬盤空間的做法。


4.在列上構造索引

在需要經常使用在where子句後的字段上創建索引

a.單列索引、多列索引

多個單列索引與單個多列索引的查詢效果不同,因爲執行查詢時,MySQL只能使用一個索引,會從多個索引中選擇一個限制最爲嚴格的索引。

b.組合索引(最左前綴)(聚集索引)

平時用的SQL查詢語句一般都有比較多的限制條件,所以爲了進一步榨取MySQL的效率,就要考慮建立組合索引.

例如上表中針對title和time建立一個組合索引:ALTER TABLE article ADD INDEX index_titme_time (title(50),time(10))。

建立這樣的組合索引,其實是相當於分別建立了下面兩組組合索引:

–title,time

–title

爲什麼沒有time這樣的組合索引呢?這是因爲MySQL組合索引“最左前綴”的結果。簡單的理解就是隻從最左面的開始組合。並不是只要包含這兩列的查詢都會用到該組合索引,如下面的幾個SQL所示:

–使用到上面的索引

SELECT * FROM article WHREE title='測試' AND time=1234567890;

SELECT * FROM article WHREE title='測試';

–不使用上面的索引(這就是組合索引的特點)

SELECT * FROM article WHREE time=1234567890;


5.如何合理的創建索引

a. 何時使用聚集索引或非聚集索引?


動作描述使用聚集索引使用非聚集索引

列經常被分組排序使用使用

返回某範圍內的數據使用不使用

一個或極少不同值不使用不使用

小數目的不同值使用不使用

大數目的不同值不使用使用

頻繁更新的列不使用使用

外鍵列使用使用

主鍵列使用使用

頻繁修改索引列不使用使用

b.索引不會包含有NULL值的列

只要列中包含有NULL值都將不會被包含在索引中,複合索引中只要有一列含有NULL值,那麼這一列對於此複合索引就是無效的。所以我們在數據庫設計時不要讓字段的默認值爲NULL。

c.使用短索引

對串列進行索引,如果可能應該指定一個前綴長度。例如,如果有一個CHAR(255)的列,如果在前10個或20個字符內,多數值是惟一的,那麼就不要對整個列進行索引。短索引不僅可以提高查詢速度而且可以節省磁盤空間和I/O操作。

d.索引列排序

MySQL查詢只使用一個索引,因此如果where子句中已經使用了索引的話,那麼order by中的列是不會使用索引的。因此數據庫默認排序可以符合要求的情況下不要使用排序操作;儘量不要包含多個列的排序,如果需要最好給這些列創建複合索引。

e.like語句操作

一般情況下不鼓勵使用like操作,如果非使用不可,如何使用也是一個問題。like “%aaa%” 不會使用索引而like “aaa%”可以使用索引。

f.不要在列上進行運算

例如:select * from users where YEAR(adddate)<2007,將在每個行上進行運算, 這將導致索引失效而進行全表 掃描,因此我們可以改成:select * from users where adddate<’2007-01-01′。關於這一點可以圍觀: 一個單引號引發的MYSQL性能損失。

g.索引的適用條件

MySQL只對一下操作符才使用索引:<,<=,=,>,>=,between,in,以及某些時候的like(不以通配符%或_開頭的情形)。而理論上每張表裏面最多可創建16個索引,不過除非是數據量真的很多,否則過多的使用索引也不是那麼好玩的,比如我剛纔針對text類型的字段創建索引的時候,系統差點就卡死了。


二、鍵約束

鍵是比索引更高一個層次的約束,通過創建key時,數據庫會自動在該字段上創建索引。所以可以說鍵是在索引的基礎上實現的。鍵有2種:主鍵和外鍵。

1.主鍵PRIMARY KEY

a.主鍵的作用:(唯一非空約束)

主鍵是對該字段上的記錄的約束:使得該字段不能重複也不能爲空,所以主鍵被認爲是NOT NULL和UNIQUE約束最好的結合,就像記錄的×××一樣,因此一個表只能有一個主鍵 。如果這些列沒有被明確地定義爲NOT NULL,MySQL會隱含地定義這些列。

(插入記錄時,自動檢查該字段是否唯一非空)

b.聲明主鍵的方法:

CREATE TABLE tbl_name ([字段描述省略...], PRIMARY KEY(index_col_name));

LTER TABLE tbl_name ADD PRIMARY KEY (index_col_name,…);

c.組合主鍵(聯合主鍵)

主鍵分爲單主鍵和聯合主鍵。鍵生於索引而高於索引。主鍵其實也是索引,甚至在MySQL的術語裏面“鍵”就等於“索引”,所以“外鍵”一定要先設爲“索引”,這個咱們下篇日誌再來討論。所以主鍵也應該和索引一樣,既可以作用於單獨的字段,又可以作用於多個字段。組合的主鍵,每個列都會隱含定義NOT NULL約束,且其二者加在一起被定義了UNIQUE 惟一約束。將會把多字段的組合約束爲唯一非空。

create table firewall(

host varchar(11) not null,

port smallint(4),

access enum('deny', 'allow') not null,

primary key (host,port)

)


INSERT INTO firewall (host ,port ,access)

VALUES ('202.65.3.87', '21', 'deny');

/*插入一條新的記錄,沒有啥問題1 row(s) inserted.*/

INSERT INTO firewall (host ,port ,access)

VALUES ('202.65.3.87', '21', 'deny');

/*插入失敗,因爲host 加port的主鍵值202.65.3.87-21已經存在了

#1062 - Duplicate entry '202.65.3.87-21' for key 'PRIMARY'

*/

INSERT INTO firewall( host, port, access )

VALUES ('192.168.0.1', NULL , 'deny')

/*

沒聲明NOT NULl port也不能爲NULL

#1048 - Column 'port' cannot be null

*/


組合主鍵約束:組合後的字段不能爲空,也不能重複。


2.外鍵foreign key(子表約束)

只有InnoDB類型的表纔可以使用外鍵,mysql默認是MyISAM,這種類型不支持外鍵約束.

建立外鍵的表,被稱爲子表;被引用的表叫做主表或外表。一個表可以有多個外鍵,表的外鍵必須建立在另一個表的主鍵上。

外鍵:它是表中的一個已經存在的字段,可以不是本表的主鍵,但是必須對應主表中的主鍵。如果沒有delete或者update聯動約束,不能刪除主表中與該表具有關聯關係的行,但可以刪除還沒有映射關係的行。

a.外鍵的作用:(子集約束:對主表和子表都有一定的約束)

外鍵用來在2個表的數據之間建立參照完整性,即同時增刪改。若B表字段有以A表字段作爲參照的外鍵,則B表中的此字段的取值只能是A表中存在的值(該字段上,子表是主表的子集),從表B會實時受到主表A的約束,同時若關聯on delete on update等操作則當A中的被參照的字段發生delete或update時,B中的對應的記錄也會發生 delete 或 update操作,完整性;如果沒有設置delete或者update聯動,則當刪除A表中的記錄時,如果B表中存 在對應的記錄是不能刪除成功的,此時會報錯(因爲那樣將不滿足子集約束)。(總結爲:以某一個表A的某一個或組合字段約束另一個表B的某一個或組合字段,要求B表該字段的記錄是A表該字段記錄的子集,只要滿足子集約束的操作都可以,反正則不可以)


b.創建的步驟

指定主鍵關鍵字: foreign key(列名)

引用外鍵關鍵字: references <外鍵表名>(外鍵列名)

c.外鍵關聯事件觸發限制:on delete和on update , 可設參數cascade(跟隨外鍵改動), restrict(限制外表中的外鍵改動),set Null(設空值),set Default(設默認值),[默認]no action

create table temp(

id int,

name char(20),

foreign key(id) references outTable(id) on delete cascade on update cascade);

把id列設爲外鍵,參照外表outTable的id列,當外表中外鍵的值刪除,本表中對應的id記錄刪除,當外鍵的值改變 本表中對應的列值改變。

d.組合外鍵

只能有一個外鍵,但可以使用多表的字段組合成一個複合外鍵。不推薦

e.完全允許多對對的關係

主表中的一記錄可以對應子表中的多個記錄;而主表中的多個記錄也可以對應子表中的一個記錄

mysql> show create table  parent;   //主表

CREATE TABLE `parent` (

  `id` int(11) NOT NULL,

  `name` char(4) DEFAULT NULL,

  PRIMARY KEY (`id`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8 


mysql> show create table  child;    //子表

CREATE TABLE `child` (

  `id` int(11) NOT NULL,

  `parent_id` int(11) NOT NULL,

  KEY `parent_id` (`parent_id`),

  CONSTRAINT `child_ibfk_1` FOREIGN KEY (`parent_id`) REFERENCES `parent` (`id`) ON DELETE CASCADE

) ENGINE=InnoDB DEFAULT CHARSET=utf8


mysql> select * from child;

+----+-----------+

| id | parent_id |

+----+-----------+

|  1 |         1 |   //多個子表的id對應同一主表的parent_id,

|  3 |         1 |

|  1 |         2 |  //同時同一子表的id對應多個主表的parent_id

|  1 |         3 |

+----+-----------+

4 rows in set (0.00 sec)


mysql> select * from parent;

+----+------+

| id | name |

+----+------+

|  1 | a    |

|  2 | b    |

|  3 | c    |

+----+------+

3 rows in set (0.00 sec)


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章