數據庫存儲與文件結構


文件組織

一個數據庫會被映射到多個不同的文件,存儲在磁盤上,這些文件被分成特定長的存儲單元,稱為,大部分數據庫默認情況下的塊大小是4~8KB,大部分情況下這個值可以修改。

一個塊中可能包含很多條記錄,並且保證沒有一條記錄橫跨多個塊,這也限制了不可以有一條比塊更大的記錄,大部分需求中,字段只包含一些簡單的數字和文字,確實不太可能比一個塊大,對於存儲二進制文件(或其他大數據項,如圖片)的記錄,會被存儲到磁盤的其他位置,而不是我們划分出的塊上,然后在記錄中只存儲這個二進制文件的存儲地址。

還要考慮的問題是記錄是定長或者變長的問題。

定長記錄

對於這個例子,假設我們給這三個varchar變長字段都按最大長度存儲,並且每個字符占用1字節,numeric(8,2)占8字節,那么得到的長度就是\(5+20+20+8=53\)個字節

我們可以按順序在塊中存儲這些記錄,即第一條記錄占用塊的前53字節,第二條記錄占用塊的第二個53字節,像這樣

問題:

  • 如果塊的大小不是53字節的倍數,那么就會有記錄需要橫跨兩個塊
  • 刪除一個記錄后空下來的53字節我們需要想辦法處理,是讓其他記錄向前移動還是標記這個位置是空的,后面的插入可以直接使用。

第一個問題,直接棄用一個塊中最后剩下的部分即可,它肯定小於一條定長記錄的長度,否則我們就可以將這條記錄塞進去了,所以這個小空間的棄用可以接受。第二個問題,如果需要其他記錄向前移動,也有兩種辦法,第一種是將被刪除記錄后面的所有記錄都向前移動,第二種就是讓最后一個記錄向前移動到被刪除記錄的位置。

另一種處理刪除產生的空余空間的辦法是,標記這個空間是空余的,后面如果進行插入操作時直接插入到這個空余空間。這樣就需要在文件頭中額外維護一個空余空間表。文件頭指向第一個被刪除的記錄留下的空余空間的地址,這個被刪除的記錄的空間中我們暫時存儲下一個空余空間地址,這樣就形成了一個用於記錄所有空余空間的鏈表,稱作空閑列表

插入記錄時,我們就會將記錄插入到文件頭所指向的空余空間上,並修改文件頭指向下一個空余空間。

如果沒有空余空間,那么就存到文件末尾。

變長記錄

變長記錄的表示

可產生變長記錄的情況:

  1. 一個文件中存放不同種類的記錄
  2. 一個或多個字段是變長字段
  3. 允許可重復字段,如數組或集合

變長記錄可以按照如下方式分成兩部分存儲,第一部分存儲記錄中的定長字段,這部分的長度固定,第二部分存儲變長字段,然后對於變長字段,我們還需要在一個記錄的首部(也就是定長字段之前)存儲上每一個變長字段的(偏移量, 長度)。偏移量表示該字段在記錄中的起始位置,長度表示它所占用的字節數。

比如下面的例子,instructor記錄中有四個字段(ID, name, dept_name, salary),其中前三個是變長字段,第四個是占用8個字節的定長字段。

空位圖的作用是記錄字段中哪些屬性是空,如果salary是空,那么空位圖第四位就是1。如果記錄中的字段很多,空位圖的大小也會變大。

變長記錄在塊中的放置

分槽的頁結構,一般用於在塊中組織記錄,塊頭中的信息如下

  1. 記錄塊中的記錄個數
  2. 記錄塊空閑空間的尾部位置(即離頭最近的第一個記錄的位置-1)
  3. 一個包含塊中所包含的所有記錄的位置和大小的數組

所以,在這個結構中,記錄從尾部開始向前連續排列,如果插入一條記錄,那么從空閑空間的尾部向前分配記錄大小的空間給新紀錄,並且需要將這個記錄的位置和大小添加到塊頭的記錄數組中。

刪除一個記錄,這條記錄在記錄數組中被標記為刪除狀態(如它的大小被設置為-1),還需要將該記錄前面所有的記錄向后移動,並且更新它們在記錄數組中所記錄的位置。這樣刪除所得到的空余空間可以被重用。將記錄變長或變短也可以用同樣的方式。操作一個4~8KB的數據還是很快的。

分槽的頁結構中指針不能直接指向塊中的記錄,而是要指向塊頭的記錄數組

文件中記錄的組織

  • 堆文件組織:一條記錄可以放在文件中任何位置
  • 順序文件組織:根據搜索碼順序排布
  • 散列文件組織:根據元組的部分屬性計算出散列值,通過散列值確定存放位置

順序文件組織

目的是為了快速處理按某個搜索碼的順序排序的記錄而設計的。

文件中的記錄通過指針連接到按搜索碼排序的下一條數據,這樣保證了記錄之間的邏輯順序。為了減少文件處理中的塊訪問數,最好讓記錄的邏輯順序和物理順序保持一致,否則邏輯上相鄰的兩個數據可能處在不同的塊中,這樣你檢索出一批看似應該相鄰的數據就不一定要從多少塊中來拿數據了。圖中(ID為搜索碼)就是邏輯順序和物理順序完全一致的情況。

在插入和刪除記錄時又要維護整個文件的結構。

考慮插入時需要遍歷整個鏈,找到這個文件中按照搜索碼排序的前一條記錄,然后若此時這個前一條記錄所在塊中有空閑空間就插入到這個塊中,否則插入到溢出塊中,並且調整指針。

當物理順序和邏輯順序不一致達到一定程度,那么處理效率將十分低下,此時應考慮重組文件,重組文件代價很高,所以需要在系統負載很低的時候進行。當插入很少的情況下,這種組織方式能很好的運行。

多表聚簇文件組織

在處理大型數據的系統中,為了避免多個文件帶來過多的IO操作,可能會在一個文件里存入多個關系,但是盡管是這樣,大多數數據庫還是只會在同一個塊中存儲同一個關系中的元組。

考慮這樣的查詢,如果我們的系統允許在同一個塊中存儲多個關系,那么很可能我們要進行連接查詢時需要用到的兩個關系中的元組在同一個塊中,那么就避免了多次讀塊將數據從磁盤放到內存中。

select * from instructor natural join department;

最高效的文件結構就是將每個department中的元組存儲在dept_name相同的instructor元組的附近,這樣它們就在同一個塊中了,如果恰好不在同一個塊中,那么這個department元組也會在相鄰的下一個塊中。

多表聚簇文件組織適合處理多表連接查詢,但其它類型的查詢則會被拖慢,比如

select * from department;

因為每個塊存儲了多個關系中的數據,那么一個塊中的department數據就少了,需要執行查詢所必須讀取的塊就增加了。

數據字典存儲

數據庫還要存儲一些數據庫系統本身相關的數據,稱為元數據,比如

這種信息一般存儲在數據字典(data dictionary)或系統目錄(system catalog)中

我的理解就是,很多數據庫系統為了簡化系統設計,並且讓用戶可以通過與操作其他庫和表完全一致的方法來操作這些元數據,所以將元數據內建在系統中一個特殊的數據庫里,比如MYSQL的mysql庫。

然后這個庫因為需求和其他的用於存儲海量數據的庫的需求不同,所以它一般要重新設計,采用不同的存儲方式,但提供一致的操作接口。

緩沖區

在內存中緩存磁盤中的塊。

  1. 緩沖區替換策略:緩沖區沒有足夠空間容納新塊時,需要清除一個舊塊,通常使用LRU算法,即最近訪問最少的被移除
  2. 被釘住的塊:當一個塊上的更新操作正在進行時,不允許將塊寫回磁盤
  3. 塊的強制寫出:某些情況下,即使不需要這個塊的空間,也要將塊強制寫回磁盤。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM