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)