數據庫物理設計
定義:為一個給定的邏輯模型設計一個最適合應用要求的物理結構
數據庫在物理設備上的存儲結構和存取方法稱為數據庫的物理結構
物理設計涉及到的評價標准
數據存儲:
①數據量
②存取頻度
③存取方法:批處理/聯機處理;檢索/更新;順序檢索/隨機檢索
處理要求:
處理頻度要求,單位時間處理多少事務、多少數據量和響應要求等
以上兩個要求的信息都涉及到上節需求分析中的數據字典
為關系模式選擇存取方法(建立存取路徑)
數據庫常用存取方法:索引存取方法、聚簇存取方法、hash存取方法
1.索引存取方法
根據應用要求確定:
對哪些屬性列建立索引
對哪些索引設計為唯一索引,組合(復合)索引
選擇合適的索引方法(B+樹索引,hash索引)
建立索引的方法:
①建表時建立
CREATE TABLE 表名(
字段名 數據類型 [完整性約束條件],
……,
[UNIQUE | FULLTEXT | SPATIAL] INDEX | KEY
[索引名](字段名1 [(長度)] [ASC | DESC]) [USING 索引方法]
);
②建表后建立
ALTER TABLE 表名 ADD [UNIQUE | FULLTEXT | SPATIAL] INDEX | KEY [索引名] (字段名1 [(長度)] [ASC | DESC]) [USING 索引方法];
或
CREATE [UNIQUE | FULLTEXT | SPATIAL] INDEX 索引名 ON 表名(字段名) [USING 索引方法];
對什么列要建立索引:①主鍵自動建立索引
②經常作為查詢條件在WHERE和ORDER BY的語句中出現的列
③外鍵建立索引
④用於聚合函數的列,如max(column_1)中的column_1
對什么列不要建立索引:①經常刪改的列
②有大量重復的列
③表記錄太少不要建立索引
索引失效的情況:①在組合索引中不能有列值為NULL的情況
②在一個語句中索引只能用一次,如果在WHERE中用了那么在ORDER BY中就不會走索引
③LIKE操作中,'%aaa%'不會走索引,'aaa%'會走索引
對於其他通配符_ [charlist] [!charlist]也是僅當第一個字符不為通配符才走索引
④在索引的列上使用表達式或函數會使索引失效,如select * from users where YEAR(date)< 2007,這將導致進行全表掃描。
⑤只有在where子句中出現,mysql才會去使用索引
⑥如果條件中有or,即使其中有部分條件帶索引也不會使用(這也是為什么盡量少用or的原因),要想使用or,又想讓索引生效,只能將or條件中的每個列都加上索引
⑦對於復合索引,如果不使用前列,后續列也將無法使用
⑧如果mysql估計使用全表掃描要比使用索引快,則不使用索引(數據量小的表)
⑨存在索引列的數據類型隱形轉換,則不走索引,比如WHERE email=77777 不走索引
B+樹索引和hash索引
1.B+樹索引
在B+樹上,所有實際需要的數據(可以存儲整行的數據故不需要表掃描(二次查找))都存放於 Tree 的 Leaf Node ,到任何一個 Leaf Node的最短路徑的長度都是完全相同的。
可以支持順序掃描,利用雙向指針快速左右移動,效率非常高。
BTree索引是最常用的mysql數據庫索引算法,因為它不僅可以被用在=,>,>=,<,<=和between這些比較操作符上,而且還可以用於like操作符,只要它的查詢條件是一個不以通配符開頭的常量
2.hash索引
hash索引檢索時只需要進行一次hash算法就能定位到相應的hash值鏈表中,得到行指針再進行表訪問,一般來說速度優於BTree索引
①hash索引不能范圍查詢只能等值查詢(包括=、 IN 、<=>)
②hash索引不能用於排序oder by,因為hash是按hash值存儲的,原值不同可能hash值也是相同的
③hash索引不能避免表掃描(二次查找),即hash索引本身並不存儲信息(元組)僅存儲行指針,所以還要返回表中找到對應行
④hash索引不支持組合索引的部分索引查找(也不支持最左匹配),組合索引是各部分一起計算hash值存儲在hash表中的,只能用於組合索引所有部分都出現的等值查找的情況
⑤hash碰撞問題。當有大量重復鍵的時候hash索引性能極低,可能低於BTree
索引的缺點
索引的缺點
◆維護索引的開銷:雖然索引大大提高了查詢速度,同時卻會降低更新表的速度,如對表進行 INSERT、UPDATE和DELETE。因為更新表時,MySQL不僅要保存數據,還要保存一下索引文件。
◆存儲索引的開銷:建立索引會占用磁盤空間的索引文件。一般情況這個問題不太嚴重,但如果你在一個大表上創建了多種組合索引,索引文件的會膨脹很快。
最左匹配原則
最左匹配原則僅存在於復合索引:
以該表的(name,cid)復合索引為例,它內部結構簡單說就是下面這樣排列的
mysql創建復合索引的規則是首先會對復合索引的最左邊的,也就是第一個name字段的數據進行排序,在第一個字段的排序基礎上,然后再對后面第二個的cid字段進行排序。其實就相當於實現了類似 order by name cid這樣一種排序規則。
所以:第一個name字段是絕對有序的,而第二字段就是無序的了。所以通常情況下,直接使用第二個cid字段進行條件判斷是用不到索引的,當然,可能會出現上面的使用index類型的索引。這就是所謂的mysql為什么要強調最左前綴原則的原因。
那么什么時候才能用到呢?
當然是cid字段的索引數據也是有序的情況下才能使用咯,什么時候才是有序的呢?觀察可知,當然是在name字段是等值匹配的情況下,cid才是有序的。發現沒有,觀察兩個name名字為 c 的cid字段是不是有序的呢。從上往下分別是4 5。
這也就是mysql索引規則中要求復合索引要想使用第二個索引,必須先使用第一個索引的原因。(而且第一個索引必須是等值匹配)。
---------------------------------------------------------------------------------------------------------------------------
所以對於你的這條sql查詢:
EXPLAIN SELECT * FROM student WHERE cid=1 AND name='小紅';
沒有錯,而且復合索引中的兩個索引字段都能很好的利用到了!因為語句中最左面的name字段進行了等值匹配,所以cid是有序的,也可以利用到索引了。
你可能會問:我建的索引是(name,cid)。而我查詢的語句是cid=1 AND name='小紅'; 我是先查詢cid,再查詢name的,不是先從最左面查的呀?
好吧,我再解釋一下這個問題:首先可以肯定的是把條件判斷反過來變成這樣 name='小紅' and cid=1; 最后所查詢的結果是一樣的。
那么問題產生了?既然結果是一樣的,到底以何種順序的查詢方式最好呢?
所以,而此時那就是我們的mysql查詢優化器該登場了,mysql查詢優化器會判斷糾正這條sql語句該以什么樣的順序執行效率最高,最后才生成真正的執行計划。所以,當然是我們能盡量的利用到索引時的查詢順序效率最高咯,所以mysql查詢優化器會最終以這種順序進行查詢執行。
2.聚簇存取方法
聚簇索引,實際存儲的循序結構與數據存儲的物理機構是一致的,所以通常來說物理順序結構只有一種,那么一個表的聚簇索引也只能有一個,通常默認都是主鍵,設置了主鍵,系統默認就為你加上了聚簇索引。
當然有人說我不想拿主鍵作為聚簇索引,我需要用其他字段作為索引,當然這也是可以的,這就需要你在設置主鍵之前自己手動的先添加上唯一的聚簇索引,然后再設置主鍵,這樣就木有問題啦。
總而言之,聚簇索引是順序結構與數據存儲物理結構一致的一種索引,並且一個表的聚簇索引只能有唯一的一條;
InnoDB使用的是聚簇索引,將主鍵組織到一棵B+樹中,而行數據就儲存在葉子節點上,若使用"where id = 14"這樣的條件查找主鍵,則按照B+樹的檢索算法即可查找到對應的葉節點,之后獲得行數據。
InnoDB本質上是沒有hash索引的,hash索引是“索引的索引”,InnoDB為了加速索引的查找會建立自適應(adaptive)hash表。
hash索引常用於內存數據庫Memory/Heap引擎。
MySQL早期采用的MyISAM引擎和后來采用的InnoDB:
InnoDB是聚集索引,使用B+Tree作為索引結構,數據文件是和(主鍵)索引綁在一起的(表數據文件本身就是按B+Tree組織的一個索引結構),必須要有主鍵,通過主鍵索引效率很高。但是輔助索引需要兩次查詢,先查詢到主鍵,然后再通過主鍵查詢到數據。因此,主鍵不應該過大,因為主鍵太大,其他索引也都會很大。
MyISAM是非聚集索引,也是使用B+Tree作為索引結構,索引和數據文件是分離的,索引保存的是數據文件的指針。主鍵索引和輔助索引是獨立的。
也就是說:InnoDB的B+樹主鍵索引的葉子節點就是數據文件,輔助索引的葉子節點是主鍵的值;而MyISAM的B+樹主鍵索引和輔助索引的葉子節點都是數據文件的地址指針。
使用聚簇索引的優勢:
1.由於行數據和聚簇索引的葉子節點存儲在一起,同一頁中會有多條行數據,訪問同一數據頁不同行記錄時,已經把頁加載到了Buffer中(緩存器),再次訪問時,會在內存中完成訪問,不必訪問磁盤。這樣主鍵和行數據是一起被載入內存的,找到葉子節點就可以立刻將行數據返回了,如果按照主鍵Id來組織數據,獲得數據更快。
2.輔助索引的葉子節點,存儲主鍵值,而不是數據的存放地址。好處是當行數據放生變化時,索引樹的節點也需要分裂變化;或者是我們需要查找的數據,在上一次IO讀寫的緩存中沒有,需要發生一次新的IO操作時,可以避免對輔助索引的維護工作,只需要維護聚簇索引樹就好了。另一個好處是,因為輔助索引存放的是主鍵值,減少了輔助索引占用的存儲空間大小。
為關系、索引、日志、備份等數據庫文件選擇存儲結構
存儲的對象:關系、索引、日志、備份、數據庫緩沖區
存儲的方式:內存/磁盤,行/列存儲,集中/分散存儲,隨機/順序/聚簇存儲
選擇存儲結構的基本原則
①易變部分與穩定部分分開存放
②經常存取部分與存取頻率低部分分開存放
③日志文件與數據庫對線(表、索引)分開存放
DBMS一般都提供了一些存儲分配參數:同時用戶數、同時對象數、內存分配參數、緩沖區分配參數、鎖數目……