鍵、索引、約束及其區別
今天下午剛好沒事,把一些基礎性的概念理順一下,存檔,省的麻煩,嘿嘿
一.索引
1. 什么是索引?
索引是對數據庫表中一列或多列的值進行排序的一種結構。
在關系型數據庫中,索引是一種與表有關的數據庫結構,是事實存在的。它可以使對於表的select等等操作更加快速,相當於一本書的目錄。
對於一張表,如果我們想要找到某一列符合特定值的記錄,第一種方法是全表搜索,匹配,然后把所有符合的記錄列出,但是這樣做會消耗大量數據庫系統時間,並造成大量磁盤I/O操作;第二種就是在表中建立索引,然后在索引中找到符合查詢條件的索引值,最后通過保存在索引中的ROWID(相當於頁碼)快速找到表中對應的記錄。
索引是一個單獨的、物理的數據庫結構,它是某個表中一列或若干列值的集合和相應的指向表中物理標識這些值的數據頁的邏輯指針清單。由此可知,索引是要消耗數據庫空間的。
並非所有的數據庫都以相同的方式使用索引。作為通用規則,只有當經常查詢索引列中的數據時,才需要在表上創建索引。索引占用磁盤空間,並且降低添加、刪除和更新行的速度。在多數情況下,索引用於數據檢索的速度優勢大大超過它的不足之處。但是,如果應用程序非常頻繁地更新數據或磁盤空間有限,則可能需要限制索引的數量。
可以使用單列作為索引,也可以使用多列聯合作為索引。
2. 索引的優缺點
優點:
(1)大大加快數據的檢索速度;
(2)創建唯一性索引,保證數據庫表中每一行數據的唯一性;
(3)加速表和表之間的連接;
(4)在使用分組和排序子句進行數據檢索時,可以顯著減少查詢中分組和排序的時間。
缺點:
(1)索引需要占物理空間。
(2)當對表中的數據進行增加、刪除和修改的時候,索引也要動態的維護,降低了數據的維護速度。
建立索引時的注意事項:
(1) 考慮已在表上創建的索引數量。最好避免在單個表上有很多索引
(2) 檢查已在表上創建的索引的定義。最好避免包含共享列的重疊索引
(3) 檢查某列中唯一數據值的數量,並將該數量與表中的行數進行比較。比如如果有1000w記錄,某字段為性別,只有男,女。也就是說一半的記錄都是重復的,這樣就要考慮是否還有必要建立索引了。
3. 一些索引類別
(1) 普通索引
也即不加任何限制的索引。可通過以下語句理解。
create table zjj_temp_1 (id number(10),first_name char(10),last_name char(10),age number(3),val number(10,2));
insert into zjj_temp_1 values(1,'junjie','zhang',25,4000);
select * from zjj_temp_1;
此時一條記錄已經插入進入了。
create index zjj_temp_index_1 on zjj_temp_1(first_name);
--------建立索引
insert into zjj_temp_1 values(1,'junjie','zhang',25,4000)
--------再次插入一條一模一樣的記錄
select * from zjj_temp_1;
Ok!兩條記錄出現了,也即此索引的作用是讓你再查找first_name為某一個特定值的記錄時速度更快而已,僅此而已。
(2) 唯一索引
一種索引,不允許具有索引值相同的行,從而禁止重復的索引或鍵值。系統在創建該索引時檢查是否有重復的鍵值,並在每次使用 INSERT 或 UPDATE 語句添加數據時進行檢查。
繼續分析例子:
drop index zjj_temp_index_1; ----刪除上文創建的普通索引。
create unique index zjj_temp_1 on zjj_temp_1(id);
----建立唯一索引
數據庫報錯了?
是的,說找到重復的關鍵字。
從上文我們可以看到,zjj_temp_1表中有兩條記錄,id都是1.
這樣是唯一索引是不允許的,所以自然就創建不起來了。
delete from zjj_temp_1 where rownum<2; --刪除一行
create unique index zjj_temp_1 on zjj_temp_1(id);
----繼續創建,發現這次成功了。
insert into zjj_temp_1 values(2,'junjie','zhang',25,4000);
----成功
insert into zjj_temp_1 values(1,'kesi','ma',25,4000); 失敗!!!
耶!就是這樣!
(3) 主鍵索引
數據庫表經常有一列或列組合,其值唯一標識表中的每一行。該列稱為表的主鍵。它和唯一索引的共性在於都不允許有重復記錄,區別在於,唯一索引是不限制null的,也就是說或可以有一條以上的null值插入,但是主鍵卻限定不能為空。
繼續執行語句:
insert into zjj_temp_1 values(null,'kesi','ma',25,4000); ---成功
select * from zjj_temp_1;
這就表明唯一索引是允許有空值的。
Drop index zjj_temp_1; ---刪除唯一索引
alter table zjj_temp_1 add constraint zjsy_1 primary key(id); ---建立主鍵
我們可以發現id有一條記錄為空,所以是無法建立主鍵的。
刪除那條空記錄就可以了。
(4) 聚簇索引和非聚簇索引
聚簇索引也叫簇類索引,是一種對磁盤上實際數據重新組織以按指定的一個或多個列的值排序。由於聚簇索引的索引頁面指針指向數據頁面,所以使用聚簇索引查找數據幾乎總是比使用非聚簇索引快。每張表只能建一個聚簇索引,並且建聚簇索引需要至少相當該表120%的附加空間,以存放該表的副本和索引中間頁。
聚簇是根據碼值找到數據的物理存儲位置,從而達到快速檢索數據的目的。Oracle聚簇索引的順序就是數據的物理存儲順序,葉節點就是數據節點。非聚簇索引的順序與數據物理排列順序無關,葉節點仍然是索引節點,只不過有一個指針指向對應的數據塊。由於聚簇索引要按照索引排序,所以一個表最多只能有一個聚簇索引,但可以使用多列。
ORACLE中的聚簇表是指兩個表有一個字段完全相同,並且在業務中經常會按這個字段為目標連接這兩個表,這時建立聚簇表,
兩個表公用一個字段,能減少占用空間,並能明顯提高連接查詢速度。
這兩篇都有實際的例子,這里就不再深入討論了。
建立聚簇索引的思想
1、大多數表都應該有聚簇索引或使用分區來降低對表尾頁的競爭,在一個高事務的環境中,對最后一頁的封鎖嚴重影響系統的吞吐量。
2、在聚簇索引下,數據在物理上按順序排在數據頁上,重復值也排在一起,因而在那些包含范圍檢查(between、<、<=、<>、>=)或使用group by或orderby的查詢時,一旦找到具有范圍中第一個鍵值的行,具有后續索引值的行保證物理上毗連在一起而不必進一步搜索,避免了大范圍掃描,可以大大提高查詢速度。
3、在一個頻繁發生插入操作的表上建立聚簇索引時,不要建在具有單調上升值的列(如IDENTITY)上,否則會經常引起封鎖沖突。
4、在聚簇索引中不要包含經常修改的列,因為碼值修改后,數據行必須移動到新的位置。
5、選擇聚簇索引應基於where子句和連接操作的類型。
具體的聚簇索引請參考以下文章:
http://blog.sina.com.cn/s/blog_607b68cc0100f5jo.html
http://space.itpub.net/9778796/viewspace-660186
二.鍵
1. 什么叫鍵
數據庫中的鍵(key)又稱為關鍵字,是關系模型中的一個重要概念,它是邏輯結構,不是數據庫的物理部分。
2. 唯一鍵
唯一鍵,即一個或者一組列,其中沒有重復的記錄。可以唯一標示一條記錄。
3. 主鍵
屬於唯一鍵,是一個比較特殊的唯一鍵。區別在於主鍵不可為空。
4. 外鍵
如果公共關鍵字在一個關系中是主關鍵字,那么這個公共關鍵字被稱為另一個關系的外鍵。由此可見,外鍵表示了兩個關系之間的聯系。以另一個關系的外鍵作主關鍵字的表被稱為主表,具有此外鍵的表被稱為主表的從表。外鍵又稱作外關鍵字。換而言之,如果關系模式R中的某屬性集不是R的主鍵,而是另一個關系R1的主鍵則該屬性集是關系模式R的外鍵,通常在數據庫設計中縮寫為FK。
外鍵在開發中基本使用不到,主要是數據庫用來保證數據的完整性的
舉個簡單的例子
表A內有列C1
表B內有列C2
將C2的外鍵指向C1
那么當你向表B插入數據時,C2的內容必須為C1中的一個
還有幾個約束需要你設置
如刪除或者修改表A中的字段時怎么處理表B中相關聯的數據
舉例如下:
create table z_laopo (id number(5) primary key,name char(20),age number(3),zhiye char(20)); ----創建老婆表
create table z_nanren
(id number(5) primary key,
name char(20),
age number(3),
laopo_id number(5),
foreign key(laopo_id) references z_laopo(id)
); -----創建男人表,並限定laopo_id為老婆表的外鍵
insert into z_laopo values (1,'fengjie',18,'accontant');
insert into z_laopo values (2,'cangjingkong',25,'teacher');
----向老婆表插入記錄
insert into z_nanren values (1,'nanren_1',24,1)
insert into z_nanren values (2,'nanren_2',24,2)
insert into z_nanren values (3,'nanren_3',24,3)
----向男人表也插入3條記錄
前兩條沒問題,第三條報錯:
因為不存在id為3的老婆,也即laopo_id只能再1,2之間選擇。除非z_laopo表中有3這個id。
5. 父鍵
對於有外鍵關系的2張表,存在外鍵的表所參照的表叫主表,而存在外鍵的表叫從表,上例中z_nanren為從表,z_laopo為主表。Lao_id為外鍵,z_laopo表的id為父鍵。
三.約束
像主鍵、唯一等等其實都是一種約束。
看一下語句就能明白了
create table z_test1(a char(10)); ---創建表
alter table z_test1 add constraint PK_Z_TEST1 primary key(a);
----添加主鍵
create table z_test2(a char(10)); ---創建表
alter table z_test2 add constraint UQ_Z_TEST1 unique(a); ----添加唯一約束
其中主鍵約束比唯一約束更嚴格,不能為空。
四.鍵、索引、約束的區別
一般,我們看到術語“索引”和“鍵”交換使用,但實際上這兩個是不同的。索引是存儲在數據庫中的一個物理結構,鍵純粹是一個邏輯概念。鍵代表創建來實施業務規則的完整性約束。索引和鍵的混淆通常是由於數據庫使用索引來實施完整性約束。
(1) 主鍵索引和主鍵有什么關系?
主鍵索引是創建主鍵的時候系統自動創建的索引,主鍵要求不重復,不為空,但是他如何判斷有效率呢?當然是建索引了,老是全表遍歷還不瘋掉。
所以建立主鍵會自動的建立主鍵索引。
(2) 主鍵和唯一鍵的區別在於唯一鍵可以為空,主鍵不可以
(3) 建立唯一約束和唯一索引又什么區別?
同理,建立唯一約束的時候,也會自動的創建唯一索引。建立唯一索引可以說是唯一約束的一種手段。
基本上,實現起來是沒有什么區別的。如果實在理解不了,就當一樣好了。
(4) 聚簇索引和非聚簇索引有何區別?
這個上邊已經講和很詳細了,還附有兩篇文章,這里就不說了。
(5) 約束和主鍵有什么區別?
約束一般有主鍵約束,外鍵約束,唯一約束等。
分別為primary key,foreign key,unique 其中主鍵約束只是約束的一種。
其實他們是不同概念的東西。
Ok,基本就整理成這樣吧!
原文地址:http://blog.sina.com.cn/s/blog_82ee2ee60100xwl4.html
這篇文章的意義已經理解,但是他舉得例子不錯,保存下來,下次想看的時候可以參考一下。
一般,我們看到術語“索引”和“鍵”交換使用,但實際上這兩個是不同的。索引是存儲在數據庫中的一個物理結構,鍵純粹是一個邏輯概念。鍵代表創建來實施業務規則的完整性約束。索引和鍵的混淆通常是由於數據庫使用索引來實施完整性約束。
接下來我們看看數據庫中的主鍵約束、唯一鍵約束和唯一索引的區別。
SQL> select * from v$version;
BANNER
--------------------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - Production
PL/SQL Release 11.2.0.1.0 - Production
CORE 11.2.0.1.0 Production
TNS for Linux: Version 11.2.0.1.0 - Production
NLSRTL Version 11.2.0.1.0 - Production
SQL> create table test (
2 id int,
3 name varchar2(20),
4 constraint pk_test primary key(id))
5 tablespace users;
Table created.
SQL> select constraint_name, constraint_type from user_constraints;
CONSTRAINT_NAME C
------------------------------ -
PK_TEST P
在test表中,我們指定了ID列作為主鍵,Oracle數據庫會自動創建一個同名的唯一索引:
SQL> select index_name, index_type, uniqueness, tablespace_name
2 from user_indexes
3 where table_owner='SCOTT'
4 and table_name = 'TEST';
INDEX_NAME INDEX_TYPE UNIQUENES TABLESPACE_NAME
-------------------- -------------------- --------- ------------------------------
PK_TEST NORMAL UNIQUE USERS
此時,如果我們再試圖在ID列上創建一個唯一索引,Oracle會報錯,因為該列上已經存在一個唯一索引:
SQL> create unique index idx_test_uk on test(id);
create unique index idx_test_uk on test(id)
*
ERROR at line 1:
ORA-01408: such column list already indexed
即使創建非唯一索引也不行:
SQL> create index idx_test_id on test(id);
create index idx_test_id on test(id)
*
ERROR at line 1:
ORA-01408: such column list already indexed
那么唯一鍵約束的情況是怎樣的呢?
SQL> drop table test purge;
Table dropped.
SQL> create table test(
2 id int,
3 name varchar2(20),
4 constraint uk_test unique(id));
Table created.
SQL> select constraint_name, constraint_type from user_constraints;
CONSTRAINT_NAME C
------------------------------ -
UK_TEST U
查看此時的索引情況:
SQL> select index_name, index_type, uniqueness, tablespace_name
2 from user_indexes
3 where table_owner='SCOTT'
4 and table_name = 'TEST';
INDEX_NAME INDEX_TYPE UNIQUENES TABLESPACE_NAME
-------------------- -------------------- --------- ------------------------------
UK_TEST NORMAL UNIQUE USERS
Oracle同樣自動創建了一個同名的唯一索引,而且也不允許再在此列上創建唯一索引或非唯一索引。
我們知道,主鍵約束要求列值非空(NOT NULL),那么唯一鍵約束是否也要求非空呢?
SQL> insert into test values(1, 'Sally');
1 row created.
SQL> insert into test values(null, 'Tony');
1 row created.
SQL> insert into test values(null, 'Jack');
1 row created.
SQL> select * from test;
ID NAME
---------- --------------------
1 Sally
Tony
Jack
從實驗結果來看,唯一鍵約束並沒有非空要求。
接下來我們看看唯一索引對列值的非空要求有什么不同。
SQL> drop table test purge;
Table dropped.
SQL> create table test(
2 id int,
3 name varchar2(20));
Table created.
SQL> create unique index idx_test_id on test (id);
Index created.
SQL> insert into test values(1, 'Sally');
1 row created.
SQL> insert into test values(null, 'Tony');
1 row created.
SQL> insert into test values(null, 'Jack');
1 row created.
SQL> select * from test;
ID NAME
---------- --------------------
1 Sally
Tony
Jack
通過實驗,我們看出唯一索引與唯一鍵約束一樣對列值非空不做要求。
如果我們讓主鍵約束或者唯一鍵約束失效,Oracle自動創建的唯一索引是否會受到影響?
SQL> drop table test purge;
Table dropped.
SQL> create table test(
2 id int,
3 name varchar2(20),
4 constraint uk_test unique(id));
Table created.
SQL> select index_name, index_type, uniqueness from user_indexes;
INDEX_NAME INDEX_TYPE UNIQUENES
------------------------------ --------------------------- ---------
UK_TEST NORMAL UNIQUE
SQL> alter table test disable constraint uk_test;
Table altered.
SQL> select index_name, index_type, uniqueness from user_indexes;
no rows selected
當主鍵約束或者唯一鍵約束失效時,Oracle會刪除隱式創建的唯一索引。
如果我們先創建唯一索引,再創建主鍵或者唯一鍵約束,情況又會怎樣呢?
SQL> drop table test purge;
Table dropped.
SQL> create table test(
2 id int,
3 name varchar2(20));
Table created.
SQL> create unique index idx_test_id on test (id);
Index created.
SQL> select index_name, index_type, uniqueness
2 from user_indexes
3 where table_owner = 'SCOTT'
4 and table_name = 'TEST';
INDEX_NAME INDEX_TYPE UNIQUENES
------------------------------ --------------------------- ---------
IDX_TEST_ID NORMAL UNIQUE
SQL> alter table test add constraint uk_test unique (id);
Table altered.
SQL> select index_name, index_type, uniqueness
2 from user_indexes
3 where table_owner = 'SCOTT'
4 and table_name = 'TEST';
INDEX_NAME INDEX_TYPE UNIQUENES
------------------------------ --------------------------- ---------
IDX_TEST_ID NORMAL UNIQUE
SQL> select constraint_name, constraint_type
2 from user_constraints
3 where table_name = 'TEST';
CONSTRAINT_NAME C
------------------------------ -
UK_TEST U
SQL> alter table test disable constraint uk_test;
Table altered.
SQL> select constraint_name, constraint_type, status
2 from user_constraints
3 where table_name = 'TEST';
CONSTRAINT_NAME C STATUS
------------------------------ - --------
UK_TEST U DISABLED
SQL> select index_name, index_type, uniqueness, status
2 from user_indexes
3 where table_owner = 'SCOTT'
4 and table_name = 'TEST';
INDEX_NAME INDEX_TYPE UNIQUENES STATUS
------------------------------ --------------------------- --------- --------
IDX_TEST_ID NORMAL UNIQUE VALID
實驗結果表明,先創建的唯一索引不受約束失效的影響。
總結如下:
(1)主鍵約束和唯一鍵約束均會隱式創建同名的唯一索引,當主鍵約束或者唯一鍵約束失效時,隱式創建的唯一索引會被刪除;
(2)主鍵約束要求列值非空,而唯一鍵約束和唯一索引不要求列值非空;
(3)相同字段序列不允許重復創建索引;