我發起了一個 .Net 開源 數據庫 項目 SqlNet

你們好 , 我發起了一個 .Net 開源 數據庫 項目 SqlNet 。html

項目計劃 是 用 C# 寫一個 關係數據庫 。算法

能夠先參考我以前寫的 2 篇文章 :    數據庫

談談數據庫原理    http://www.javashuo.com/article/p-twiqbcgi-cb.html架構

論數據庫 B Tree 索引在固態硬盤上的離散存儲    http://www.javashuo.com/article/p-dosbndbx-bs.html併發

 

根據 上面說的 , SqlNet 中的 表數據 和 索引數據 的 存儲 打算使用 鏈式存儲(離散存儲) 。分佈式

但這樣的作法是 存在一些 風險 或者說 可能的問題 的 。性能

由於 現有的     文件流  驅動程序  硬件控制指令  硬件控制電路     都是 基於 順序讀寫 的 模式 來 設計 的 , 因此用 順序讀寫 架構下的 指令 來 實現 隨機讀寫 , 效率應該會有所下降 。 簡單的 , 咱們能夠這樣看 , 在現有的架構下 , 須要 2 個步驟來完成 1 次 隨機讀寫 : 1 設定流位置(Position) , 2 讀寫 。 而真正的 隨機讀寫 應該是像 讀寫內存 同樣 在一個 指令裏 指定 地址 + 數據 , 1 個指令就完成對指定地址的讀寫 。測試

這中間可能還有不少細節 , 不過這個要測試起來應該很麻煩 , 並且本身測試不必定準確 , 因此懶得測了 , 就按照這個設計開始 吧 。  ^ ^大數據

咱們能夠參考這篇文章 :http://ssd.zol.com.cn/608/6082318.html  優化

這篇文章是 固態硬盤 性能測試報告 , 包括了 連續讀 連續寫 隨機讀 隨機寫 , 其中所說的 「Intel 600P」 的 連續讀能夠達到 1800M/s ,連續寫能夠達到 500M/s , 隨機讀接近 480M/s , 隨機寫接近 400M/s 。  因此 。

文中的 隨機讀 和 隨機寫 是 指 「4K隨機讀」 和 「4K隨機寫」 , 就是說是以 4K 爲基本單位 進行 隨機讀寫 , 而咱們的 數據庫 的 隨機讀寫 的 單位在 insert 的時候是 行 。一個欄位比較多的行 , 數據量多是 1K , 若是 欄位比較多 , 欄位裏的內容也比較長(好比 字符串比較長) , 那麼也很容易達到 4K  。 因此 4K 做爲讀寫的 最小單位 進行的測試 基本上 跟 咱們的 數據庫 的 使用場景 也差很少 。 固然 update 和 delete 的 寫入 數據量 會 比較小 , update 只寫入更i新的欄位數據 , delete 只修改 行 的 上一行 的 Next 指針 , 以及將 本行 標識爲 已刪除 。

不過這些我想不是問題 , 理論上, 這些問題在將來均可以解決 。 將來出現 專門用於 固態硬盤 隨機讀寫的    文件流  驅動程序  硬件控制指令  硬件控制電路    就能夠了 。

仔細再一想 , 固態硬盤 作爲 外部設備 , 先設置 讀寫位置(Position) , 再批量讀寫 , 這個也是合理的 。

這好像有點繞 , 哈哈哈哈 。

總之 , 這麼說 , 現有的   文件流  驅動程序  硬件控制指令  硬件控制電路   若是對 SqlNet 的支持 還不是 最優 , 那麼 , 隨着技術的發展 , 是能夠獲得優化的 。

 

要 採用 鏈式存儲 , 就須要 實現 一個 內存堆 分配 的 機制 。 將 數據文件(Data File)看做一個 地址空間 , 在這個地址空間上實現一個 堆 機制 。

堆機制 能夠本身設計 , 不過 先研究一下已有的實現原理 , 好比  C# ,  Java ,  C++  的 。

採用了 鏈式存儲 , 就不須要使用傳統的  數據塊(Data Block)的存儲方式了 , 固然相對的 , 須要實現一個 堆機制 。

 

可是 仔細再一想 , 固態硬盤 是一個 外部設備 , 每一筆資料都要單獨讀取 , 這個性能消耗 應該會比 連續批量讀取 大不少 。

因此 , 我以爲仍是要採用 傳統的 Data Block 的方式 。

實際上 , Data Block 自己就是 線性表 和 鏈表 二者 的結合 。 Data Block 是一個 線性表 , 多個 Data Block 之間經過 鏈表 的 方式 鏈接起來 。

因此 , 從這裏能夠看到 , Data Block 的大小(Size)是一個 關鍵 。 Size 太大 , 則可能浪費過多的磁盤空間 , 同時 insert 時須要向後移動的 行數 也會不少 。

Size 過小 , 則讀取的效率會下降 , 最壞的狀況就是 退化 成一個 純粹的 鏈表 , 好比 每一個 Data Block 只包含 一行 。 這樣就又恢復到 「鏈式存儲」 了 。  ^^

 

什麼狀況下 , 每一個 Data Block 只包含 一行 呢 ? 好比咱們設定每一個 Data Block 的大小是 4M , 若是 1行資料 的大小 接近 4M , 那麼 , 這個 Data Block 就只能包含 1 行的 資料 。

 

因此 , 從這裏能夠看出 , Data Block 的 Size 須要根據 Table (Schema) 來決定 。 不一樣的 Table , Data Block Size  是不同的 。 或者說 , Data Block 應該叫作 「Table Block」 。

 

咱們在建立 Table 時會指定 Table Schema , 包括 有哪些列 , 列的數據類型 , 根據這些咱們能夠計算出 一行 所需的最大空間 , 咱們設定 , 1 個 Table Block 包含 1024 行 , 那麼 , 加入 1 行所需的最大空間是 4K , 那麼 , 這張 Table 的 Table Block Size 就應該是 4K * 1024 = 4M 。

 

這種作法會形成 存儲空間 的浪費 , 由於 好比 字符串類型的數據的長度 是 不定的 , 在 傳統的數據庫 中有 char , varchar , nchar , nvarchar 等 4 種類型 表示字符串 。

對於 變長字符串 , 若是要兼顧到   讀取  查找  插入  更新    的 效率 的話 , 狀況可能比較複雜 。

不過咱們能夠先實現簡單的實現 , 好比 , 咱們能夠先只支持 定長的 char 類型 。  

 

但 , 這樣根據 Table Schema 來決定 Table Block Size 的 作法 也有問題 。 在 行 size 很大時 , 會產生一些問題 。 何時 行 size 很大呢 ? 好比 列不少 , 或者 列 size 很大 , 均可能致使 行 size 很大 。 假設 行 size 是 1 M , 根據上面的設定 , 1 個 Table Block 應該有 1024 行 , 1 個 Table Block 的大小就是 1M * 1024 = 1G 。

 

1 G 的 Table Block 看起來是挺大的 , 這會致使什麼問題呢 ?  

 

在 insert 的時候 , 若是沒有 彙集索引 , 新增一行 就是將 新行 添加爲表的 最後一行 。 若是有彙集索引(好比 主鍵) , 會將 新行 根據 索引排序 插入到 指定的位置 。 而 插入 會致使 這個 Table Block 內在 這個新行 以後 的 全部 行 都 向後移動 (參考 線性表 的 插入操做)。  

1 G 的 Table Block 須要向後移動的 數據量 是 很大的 , 若是 新行 插入的位置是比較靠近 Table Block 的 開始位置 , 那麼 須要向後移動的 數據 可能 接近 1 G 。  

 

還有在 update 的時候 , 對於 長度可變 的 列 , 好比 varchar 或者 nvarchar 的 列 , 新值 若是比 舊值 的 長度 更長 , 一樣 會向後移動數據 。 須要移動 本行 的 update 的 列 以後 全部列 的數據 , 以及 本行以後 全部行 的 數據 。 

同上 , 對於 1 G 的 Table Block , 若是 update 的位置靠近 Table Block 的 開始位置 , 那麼 須要向後移動的 數據 可能 接近 1 G 。

 

因此 , 咱們仍是回到 固定大小 的 Table Block , 或者說 Data Block 。  ^^

 

對於 固定大小的 Data Block , 首先 1 行的長度不容許超過 Data Block Size 。 那麼 , 回到上面提出過的問題 , 當 行 size 比較大時 , 可能 1 個 Data Block 只包含 1 行 , 此時 , 存儲結構 將 「退化」 爲 一個 鏈表 。 但仔細一想 , 這並無關係 , 無論 1 個 Data Block 裏包含 幾行 , insert 和 update 時 須要移動的 數據 最多接近 Data Block Size 。 假設 Data Block Size 是 1 M , 那麼須要移動的數據 最多接近 1 M 。

 

對於 讀取效率 , 每次讀取的 數據 就是 1 個 Data Block , 即 1 M 。

 

綜上 , 存儲結構 的 設計 就 清楚了 , 而 在這個 存儲結構 裏 , Data Block Size 是一個 關鍵參數 。

我想 咱們能夠設定 Data Block Size 爲 1 M 。

 

下面 , 咱們先來解決 第 1 個 問題 , 索引 。

爲何 索引 是 第一個 問題呢 ? 索引是高效查詢的基礎 , 若是 表 有彙集索引(好比 主鍵) , 那麼 彙集索引 的 存儲 就是 表數據 的 存儲 。 而 主鍵 是 普遍使用的 , 甚至能夠說是 必需 的 (見 三大範式) , 根據主鍵查詢也是普遍使用的 , 因此 索引 是 第 1 個問題 , 能夠說是 數據庫 的 基礎 。 解決了 索引 的 存儲檢索 問題 , 也就解決了 數據庫 的 存儲檢索 問題 。

 

我理解的 B Tree 索引 :

實際上 , B Tree 索引 所表明的查詢原理是一種 廣泛的 索引原理 , 爲何叫 「B Tree」 , 就不知道了 。  ^^

B Tree 索引 是一個 樹形結構 , 但爲了可以從 外部存儲器(磁盤)高效的 讀取 , 咱們須要將 B Tree 索引 順序的排列起來 , 存放到 Data Block 裏 。

順序排列 起來 存放到 Data Block 裏的 B Tree 索引 以下 :

 

一個 Data Block 存放滿了 , 就存到下一個 Data Block 裏, 上文說過 , Data Block 之間經過 鏈表 的 方式鏈接起來 。 或者說 , 一張表的數據 , 或者索引 , 就是一個 Data Block 做爲元素組成的 鏈表 。

 

B Tree 索引 的 效率如何呢 ? 能夠看到 , 上面圖中的 B Tree 索引的每一個節點(索引項)有 4 個 子節點 , 這大概叫作 「4 階索引」 。 4 階索引 的 檢索流程 以下 :

假如要檢索的內容是一箇中文字符 , 按 Unicode 存儲的話 佔 2 個字節(Byte) , 對於 4 階索引來講 , 每次檢索 2 位(bit) , 2 位 表明了 4 種狀況 : 00 , 01 , 10 , 11 。

2 個字節包含了 16 位 , 那麼就要檢索 16/2 = 8 次 , (每一次檢索就是檢索一個 B Tree 節點(索引項))  。

若是要檢索的內容是一串字符 , 字符的長度是 64 個字節(Byte) , 至關因而 32 箇中文 , 那麼檢索次數是 (64 * 8) / 2 = 64 * 4 = 256 次 。

因此 B Tree 索引的 時間複雜度 和 行數 無關 , 和 檢索內容 的 長度 有關 。 具體的說, B Tree 索引的時間 複雜度 是 O(length * 8 / 2) , length 是 檢索內容 的 長度(Byte 數) 。

每次檢索(檢索一個 索引項)須要判斷 4 種狀況 : 00 , 01 , 10 , 11 , 若是 每次檢索話費的時間是 4ns (4 納秒) , 那麼查找 32 箇中文的字符串的時間就是 256 * 4ns = 1024ns  約等於 1 微秒 。

以此類推 , 查找長度爲 320 箇中文字符 的 字符串 的 時間是 1 微秒 * 10 = 10 微秒 。

查找長度爲 3200 箇中文字符 的 字符串 的 時間是 1 微秒 * 100 = 100 微秒 。

 

Sql Server 中的 nvarchar 類型 長度 可達 4000 , 就是說能夠存儲 4000 個 中文字符 。 這個能夠做爲參考 。

假設咱們的數據庫中某列 的 長度 平均 是 100 箇中文字符 , 用於查找該列的內容 也是 按 平均 100 箇中文字符計算 , 按照上面的估算 , 能夠估算按照索引查找該列的時間約是 3.4 微秒 , 假設按 4 微秒 算 , 那麼 每秒查詢次數(QPS)能夠達到 25萬次 / 秒 , 呵呵呵 , 實際能不能達到這個效果 , 就不知道了 。 須要測試 。

從這裏 , 咱們再次體會到 , 測試 是 一個 專業 , 是 和 開發 不可分割 的 一部分 , 和 開發 一塊兒組成 軟件生產力 。 測試 是 DevOps 的 主幹力量 。

等 , 我好像是 第二次 講上面這句話了 。  -_-      第一次是 在 《Socket-Vs-WebSocket-TestTool》 這篇文章裏 :  http://www.javashuo.com/article/p-kibwgbdb-u.html

 

上面的 估算 是 針對 一個 CPU 核 的 , 若是 CPU 有 多個 核 , 好比 4 核 , 那麼 QPS 能夠達到 25萬 * 4 = 100萬次 / 秒 , 若是是 8 核 , 能夠達到 25萬 * 8 = 200萬次 / 秒 。

 

B Tree 在某些場合會顯得比較 「白癡」 。 好比 只有 一行數據 , 要檢索的 列 的 長度比較長 , 好比 4000箇中文字符 , 檢索內容(查詢條件) 也是 4000箇中文字符 的 字符串 , 根據上面的 推算 , 以 4000個字符 的 字符串 做爲查詢條件 的 檢索 會 花費比較長的時間 。 而若是是循環遍歷比較字符串的話 , 只需循環 1 次 , 比較 1 次 字符串 就能夠得出結果了 。 對於 索引 而言 , 4000 個 中文字符 須要 檢索 4000 * 2 * 8 / 2 = 3.2萬 個 索引項 。 天 !   

 

看起來 索引 跑了個 馬拉松 , 而 循環遍歷 字符串 只跑了 400米 。

 

但仔細一想 , 字符串 比較 的 時間花費 跟 字符串 長度 也有關係 , 對於 ASCII 碼 的話 , 每一個字節(Byte)做一次比較 , 循環比較直到最後一個字符(若是中間有字符不一樣則可結束循環 返回 false) , 對於 Unicode 的話 , 每 2 個字節做一次比較 , 能夠理解是 1 次 Int16 整數的比較 , 但也要循環比較 4000 次 。 

 

而從這又聯想到 , 對於 大字符串 的比較有沒有更優化的算法 ? 咱們會想到計算 Hash , 能夠計算 2 個字符串的 Hash 值 進行比較 , 若相同則表示 字符串 相同 。 但 Hash 計算至關因而對 大整數 的 計算 , 具體的算法上可能也是會按 Byte 來計算 , 或者按 Int64(64位整數) 來計算 , 即對於 大字符串 , 每次取 8 個 字節(Byte) 來進行整數運算 , 以此來計算 Hash 。 但即便每次取 8 個字節 來計算 , 也要循環計算 1000 次 。

 

因此 。 而後 。

 

上述 的 效率對比問題 在    行數較少    檢索內容長度較長    的 時候都存在 。

 

索引 , 或者說 B Tree 索引 , 應該是普遍的應用於 數據存儲管理 的 各類場合 。 好比 操做系統 的 文件系統 。

這一點 , 咱們會在 《淺談操做系統原理》  http://www.javashuo.com/article/p-kfizjtdl-u.html    一文中 探討 , 固然 , 如今這篇文章裏尚未具體內容 。 嘿嘿嘿 。

 

到這裏 , 看起來 , 問題差很少解決了 。 但 , 還有一個問題 , 就是 排序規則 。

 

爲了讓數據按照人們習慣的排序方式排序 , 索引也須要 按照 人們習慣的排序方式 排序 , 實際上 , 索引 的排序規則 , 自己就是 檢索規則 。

因此 排序規則 是 索引 的 重要 組成部分 。

 

好比 , 咱們的中文習慣按照 音序 排序 , 就像 新華字典 那樣 。

那麼 , 要實現 索引 的 排序 和 按 排序規則 檢索 , 要怎麼辦呢 ?              

 

要實現 排序規則 , 須要給 字符 編一個 排序編碼 , 就像 字符編碼(好比 Unicode)那樣 。

和 Unicode 同樣 , 排序編碼 也是 2 個 字節 , 編碼是 按照 音序 來 , 好比 「啊」 字 大概是 「0000 0000 0000 0001」  吧  !

不過 上面假設是 只包含 中文 的 狀況 , 若是把 字母 和 特殊字符 包括進來 , 那 字母 和 特殊字符 應該會排在 漢字 前面 。  

 

那要怎麼知道 這個字符 的 排序編碼是 多少呢 ? 須要一張 Unicode 和 排序編碼 的 對照表 。 咱們把這個 對照表 稱爲 排序編碼表 。

這樣 根據 字符 的 Unicode 能夠查找到 對應的 排序編碼 。

排序編碼表 也是 一個 B Tree 索引 。 這樣能夠 快速查找 。

根據 Unicode 查找 排序編碼 , Unicode 的長度是 2 個 字節 , 因此查找的 時間花費 是 8 * 2 / 2 = 8 , 即 O(8) 。

因此仍是 很快的 。

 

在有 排序編碼 的狀況下 , 索引 其實是 根據 排序編碼 創建 , 檢索 也是根據 排序編碼 檢索 , 也就是說 , 索引項 裏存的 2 位(bit) 數據都是 排序編碼 的 bit 。

字符的 Unicode 只有在 索引 最終指向的 數據項 纔會 保存 。

 

有了 索引 以後 , 就能夠開始寫 數據庫引擎 了 , 索引 是 數據庫 的 基礎 。 也是 最基本單元 。

首先 , 咱們能夠用 索引 來 創建 數據庫 的 元數據 引擎 。

元數據 , 就是 有多少張表 , 每張表 有哪些列 , 列的數據類型 , 表的 起始 Data Block , 表有哪些索引 , 索引的 起始 Data Block    等等 。

數據庫 要運做 , 首先要能 高效 的 管理 和 查詢 元數據 。 這是基礎 。 在這個基礎上 , 才能進行 表 和 數據 的 存儲管理 。

 

接下來 , 咱們要對 insert update 致使 數據移動 的問題進行一些 優化 。

上文不止一次的提到 , 在 insert 和 update 可變長類型(如 varchar , nvarchar) 時 會 致使 數據移動 , 咱們再來 Review 一下 :

1 insert 會致使 Data Block 中 插入的數據 以後的數據所有要向後移動 。

2 update 可變長類型 若是 新值 比 舊值 長 , 會致使 Data Block 中 舊值 以後的數據所有要向後移動 。

3 update 可變長類型 若是 新值 比 舊值 短 , 會致使 Data Block 中 舊值 以後的數據所有要向前移動 。

上面的 3 種 狀況 至關因而 線性表 的 插入 刪除 操做 。

這些狀況 對 性能的影響是挺大的 。 因此須要做一些改良 。 能夠引入一些 「鏈式存儲」(鏈表) 的 特性 , 來彌補這部分不足 。

好比 insert 一筆資料 的時候 , 具體的舉例 , 好比 , 有一個 Data Block , 咱們稱之爲 Data Block 1 , 裏面存了 2 行 , A 行 和 C 行 。 現要在 A 行 和 C 行之間插入 B 行 , 因爲 A 行 C 行 的數據 是 順序 連續 的 排列的 , 因此若是將 B 行數據 插入在 A行 和 C 行之間 , 就會須要 C 行數據 向後移動 , 若是採用 鏈表 的 方式 , 新建一個 Data Block (稱之爲 Data Block 2) , 將 B 行寫入 Data Block 2, 讓 A 行的 Next 指針指向 Data Block 2 中的 B 行 , 同時讓 B 行的 Next 指針指向 Data Block 1 中的 C 行 。 這樣就能夠了 。這裏的 指針 包含 2 個 字段 , 一個是 Data Block 的 位置 , 另外一個是 數據在 Data Block 中的 起始位置 。 這裏的 「位置」 是指 文件流 裏的 「位置」 這個概念(如 C# 中的 FileStream.Position 屬性) 。 Data Block 的 位置是指 Data Block 在 數據文件(Data File) 中的 起始位置 , 數據在 Data Block 中的位置 指 數據的起始位置 相對於 Data Block 起始位置 的 位置 。

對於 可變長類型, 好比 varchar , nvarchar , 應採用 指針 的方式存儲 , 即 可變長類型 的 值 不保存在 行 中 , 而是 獨立存儲 , 行 經過 指針指向 值 。 在 update 時 , 若是 新值 的長度大於 舊值 , 而 舊值 後面又連續存儲了其它數據 , 則應 新申請一塊空間 來存儲 新值 , 並修改 行 內該列的指針 , 使指針指向 新值 的 位置 。 新申請的空間 可能在 同一個 Data Block 裏 , 也可能在一個 已有的 Data Block 的 空閒空間(Free Space) 裏 , 也可能會在一個 新的 Data Block 裏 。

若是 包含指針的數據 和 指針指向的數據 在 同一個 Data Block , 那麼 指針 裏的 Data Block 位置字段 能夠爲 -1 , 表示 在 同一個 Data Block 。 所謂 「包含指針的數據」 是指 好比 行 ; 「指針指向的數據」 好比 行 的 下一行 , 或者 行 的 可變長類型列的 值 。

顯然 , 這樣會形成一些 空閒空間(Free Space) , 或者 「碎片」  。

看起來咱們須要引入一些管理 空閒空間(Free Space) 的機制 。 能夠用一個 空閒空間表(Free Space List)來管理 Free Space 。Free Space List 是一個 線性表 , 長度設爲 10 , 就是說 , 最多隻保存 10 個 Free Space 。 當有超過 10 個 的 Free Space 產生時 , 若是 新的 Free Space 的大小 小於 Free Space List 中當前最小的 Free Space , 則不會添加到 Free Space List, 若是大於 , 則會 移除 當前最小的 Free Space , 將新的 Free Space 添加進 Free Space List 。

在 insert update 須要寫入數據的時候 , 就到 Free Space List 裏 查找 大小足夠 的 Free Space , 若找不到大小足夠的 Free Space , 則 申請一個新的 Data Block 。

Free Space List 的每個表項描述一個 Free Space , 表項應包含 3 個字段 , 1 Free Space 所在的 Data Block 的 起始位置 , 2 Free Space 的 起始位置 , 3 Free Space 的 結束位置 。 Free Space 的 起始位置 和 結束位置 是 相對於 Data Block 起始位置 的 相對位置 。

大量 delete 數據的時候 會產生不少 Free Space , 若是隻保存 10 個 Free Space , 會形成大量存儲空間浪費 。 算了 , 仍是 所有 Free Space 都保存吧 , 有多少保存多少 。 並且也不要 線性表 了 , 仍是用 鏈表 來做爲 Free Space List 。 這就跟 內存堆 同樣了 。 關於 內存堆 , 能夠 參考 我寫的另外一篇文章 《漫談 C++ 的 內存堆 實現原理》  http://www.javashuo.com/article/p-huenfaog-bk.html  。

若是 整個 Data Block 都空閒出來了 , 就直接歸還 數據庫引擎 , 不須要再保存到 Free Space List 。

對於 「碎片」 , 能夠經過 Job 的 方式 按期 或 不按期 整理 。

 

如今 , 在技術上 , 咱們還須要實現一個 系統 , 或者說 機制 , 或者說 庫 , 或者說 模塊 , 來實現將 數據文件(Data File)裏的 Data Block 讀取到內存裏並構成 對象圖(對象樹) 以及 將 更新過的數據寫入 數據文件 對應的 Data Block 的 對應的位置 , 或者 將 新建立的 Data Block 寫入 數據文件 。 所謂 對象圖(對象樹) , 就是 上述的 行與行 , 行與可變長類型列的值 之間的 鏈表關係(指針關係) 。

 

好了 , 有了上述的這些 , 能夠開始寫數據庫了 。

 

好的, 咱們進一步來討論一下具體的作法 。

咱們須要一個 DataManager 類 和 一個 DataBaseManager 類 。

DataManager 負責 底層 的 數據存取 。 DataBaseManager 負責 關係數據 的 管理(表 索引   ……) 。

DataBaseManager 會 調用 DataManager 。

DataManager 要實現的, 是一個 相似 內存映像 或者 虛擬內存 的 一個機制 。 將 內存 和 數據文件(Data File) , 映射成一個 虛擬的存儲空間 。 我將這個機制, 稱爲 「虛擬存儲」 。

這樣, DataBaseManager 就能夠不須要考慮 數據在 內存 和 數據文件 中存儲的 細節 而 只需 關注 關係數據 的 管理 便可 。

DataManager 要實現 內存映像 或者 虛擬內存, 能夠這樣作, 首先, 定義一個 數據存儲的單元, 相似 虛擬內存 裏的 頁, 咱們能夠叫作 Data Block 。 上文中也定義了 Data Block, 不過如今的 Data Block 和 上文的 Data Block 意義不同。 上文的 Data Block 是 關係數據層面的, 好比 一張表的 數據 會 存在多個 Data Block 中, 以及 一行資料 最大長度 不能超過 一個 Data Block 的大小 等等 。 這些對於如今的 Data Block 來說, 都不存在了 。

 

因此, 這就是 大的 架構 。

 

結論: SqlNet 是 基於 離散存儲 的 新一代 數據庫 。 離散存儲 能夠解決    大數據量大併發頻繁 insert 索引排序(移動)形成的瓶頸      的問題 。

SqlNet 的 離散存儲 基於 虛擬存儲 和 堆 。

有關於    堆  ,   我在  《漫談 C++ 的 內存堆 實現原理》   http://www.javashuo.com/article/p-huenfaog-bk.html       一文中 做了 探討 。

基於 離散存儲 的 數據庫 誕生的 土壤 是 硬件的發展, 以 固態硬盤 和 大容量內存 爲表明 。

還有另外一個因素 是 關係數據庫 的 發展到了 新的 突破 的 時候了 。

或者能夠這麼說, 離散存儲 使得 關係數據庫 向 分佈式並行計算 的 方向發展 更加 可行 和 有效 。

相關文章
相關標籤/搜索