先查询再插入的存储过程怎么写_谈一谈 InnoDB(1) - 底层存储文件结构
序
老王走進一號會議室, 隨手打開了燈, 小張緊隨其后
"王哥, 找我來干啥啊"
老王揮揮手示意小張坐下, "Boss交給了我們一個艱巨的任務, 不過你不用擔心, 最難的部分Boss已經做完了"
小張聽完松了口氣, "那我們負責干啥?"
"設計一個MySQL的數據庫引擎"
"那Boss干了啥"
"Boss把名字起好了, 叫 InnoDB"
"還有呢?" 小張一臉懵逼的看著老王
"沒了啊, 做項目最難的不就是起名字嘛" 老王隨即說到 "好了, 我們開始定下方案吧, 既然數據庫的主要功能是增刪改查, 那我們就按順序一個一個來, 先從增開始吧"
"為了之后討論方便我們先弄個表吧" 老王起身拿起馬克筆在白板上寫了一個表結構
Table Name : Userid : primaryKeyname : indexage存儲文件結構
老王 : "我們先從最底層的文件系統開始設計, 如果我要執行一條插入語句, 你覺得應該怎么持久化? 換句話說就是文件系統應該設計成什么樣子"
小張 : "嗯 ... 弄個文件一行存一條?"
老王 : "你當做畢業設計呢? 咋不弄個txt都塞進去呢"
小張 : "不是, 王哥你聽我說, 可以按照主鍵排序啊, 這樣查找的時候可以二分查找, 插入數據的話先二分查找找到對應的位置, 然后插進去就可以了"
老王 : "這個設計是有問題的, 小時候用鉛筆在田字格本上寫過作文吧? 在你寫完一篇作文之后, 你發現一個字寫錯了, 可以擦掉這個字然后改成正確的, 但是如果想在中間插一句話, 由于沒有地方給你寫, 是不是只能把后面的全部擦掉, 重新寫一遍? 硬盤就跟田字格本是一樣的, 根本不支持在隨機位置插入數據, 只能覆蓋已經有的數據. 還有一點, 田字格本是一行一行的, 但是硬盤根本沒有行這一說, 你可以理解成一頁只有一行的田字格, 隨機讀寫只支持按照字節查找, 所謂換行只不過是發現數據里有個換行符才知道你這是要換行了, 本質上換行符對于磁盤來說和其他的數據沒有什么區別, 也不知道換行符在哪兒, 所以如果你想知道一條數據是第幾行數據只能把前面的數據都掃描一遍, 這個性能就很差了"
小張 : "啊? 那我就有點懵了, 看來只能按照順序插入了? 那如果主鍵是UUID, 插入順序肯定不是有序的, 這怎么辦啊? 王哥我沒思路了"
老王 : "嗯, 有點難為你了, 你看啊, 雖然硬盤只支持按照字節查找, 但是我們可以人為的分個頁, 還是田字格本的例子, 一個本子, 每一頁的格子數目都是固定的吧, 比如說一頁有300個格子, 那我想讀第10頁, 是不是只要從第2700個格子開始讀300個格子就正好把第10頁給讀完了?"
小張 : "是這樣的, 也就是說一頁有固定的大小, 讀的時候只要知道頁數, 就可以得到頁的起始偏移量對吧, 然后呢?"
老王 : "對, 我剛才說的讀, 是指讀到內存里, 既然讀到內存里了, 那么這一頁具體有幾行, 每一行的 id 是什么是不是就都知道了? 那么現在只需要知道每個 id 所在的頁數, 那么這個問題是不是就解決了?"
小張 : "感覺還是沒懂, 這個只能在順序的情況下有用啊, 如果主鍵是UUID的話, 怎么保持數據的順序呢"
老王 : "為什么一定要按照順序保存呢? 我們可以引入索引, 就像你看書都有目錄一樣. 給你簡單的畫個圖, 就別UUID了, 太長了, 假設我們插入數據的順序按照 id 排列是 1 3 5 2 4 6 吧, 然后假設一頁能存下兩行數據, 那么等這幾條數據都被插入之后, 磁盤里的數據是這樣的"
老王 : "你看看, 這樣的話, 數據是按照插入的順序存儲的, 但是即便物理上不延續, 只要在索引上是連續的, 那么是不是無論是指定id查找還是范圍查找都很方便了?"
小張 : "是的, 王哥你真厲害, 這樣插入數據即便是亂序也不需要擦掉文件重新寫了, 只要維護好索引那個頁就好了, 那我們就照這個方案走吧"
老王 : "先別急, 你看看這個方案有什么缺點?"
小張 : "嗯 ... 要是非說缺點的話就是, 這里假設的是一頁2行數據, 如果實際上一頁放了100行數據, 那么要是按照主鍵 id 進行范圍查找的話, 由于每次讀都需要讀一整頁, 那么是不是會浪費很多IO在用不到的數據上呢?"
老王 : "嗯, 總結的非常好, 這個設計是會有這個問題, 這種設計屬于堆表的一種, 也就是存儲順序按照插入順序排放, 和索引完全解耦, 優點就是寫入很快, 缺點就是如果按照主鍵范圍查詢的話基本都是隨機讀操作, 而且由于有索引到實際數據頁的一個映射過程, 所以往往會多一次硬盤讀取"
小張 : "嗯 ... 聽你這么說, 應該還有其他更好的設計方案?
老王 : "是的, 這次的設計準備用組織索引表的設計, 不過更好倒是談不上, 兩種設計各有千秋"
小張 : "那那個什么組織索引表和堆表的區別是什么呢?"
老王 : "區別就是組織索引表的數據頁上數據存儲是有序的"
小張 : "王哥你真的不是在逗我嘛, 最開始用田字格本的例子和我說有序的存儲會需要擦掉后面的數據的不就是你嘛!"
老王 : "注意我說的是頁上的數據是有序的, 但是頁本身可以是亂序的"
小張 : "我這更糊涂了, 王哥你給舉個例子吧"
老王 : "那就還是剛才那個亂序插入 1 3 5 2 4 6 的例子吧, 給你畫個圖"
老王 : "我們來看第一個圖, 這是插入完1 3 5 三條數據的時候的結構"
小張 : "嗯, 看起來和之前那個沒什么區別, 不過這個為什么索引頁只有兩條呢"
老王 : "由于數據頁的內容都是有序的, 所以只需要標出來每一頁第一行數據的索引值就可以了, 比如如果要找 id 為 3 的數據, 先看索引頁, 發現 3 < 5 所以就去查看頁1就可以了, 如果頁1里沒有這條數據, 就說明這條數據不存在"
小張 : "嗯, 懂了"
老王 : "現在看第二張圖, 這是插入完 id 為 2 的數據的結構, 由于 id 為 2 的數據小于5所以需要插在頁1中, 但是頁1已經滿了, 所以只能將頁1從中間分開成兩個頁, 所以 id 為 1 的數據被留在了原來的頁, 2 和 3 被劃分到了一個新的頁里, 雖然 3 被從頁1移動到了頁3, 但是后續的數據,比如頁2并沒有受到影響, 所以說數據移動的開銷在可控制的范圍內"
小張 : "哦, 那第三個圖就是 id 為 4 的數據被插入, 由于頁3滿了所以新開了一個頁4, 然后 id=6 的數據由于頁2沒有滿就直接被放在了頁2上?"
老王 : "完全正確"
小張 : "那還有個問題我一至沒問, 這個索引本身也是個頁, 如果索引頁滿了怎么辦呢?"
老王 : "小伙子, 你知道B+樹嘛?"
小張 : "哦, 我明白了, 這個圖就是一層的B+樹!"
老王 : "行, 還算有點腦子, 索引頁滿了也需要分裂, 本質上和數據頁沒什么區別, 所以索引頁也不一定是連續的, 實際情況中索引頁和數據頁往往混在一起, 全靠頁指針進行查找, 還有數據頁之間應該是有指向下一個頁和上一個頁的指針的, 不過這里我沒畫出來, 看看B+樹你就明白了"
小張 : "那還有個問題, 就是這個方案好多頁都沒塞滿, 那這些空間不就浪費了嗎?"
老王 : "對, 就是浪費了, 這個沒有什么好的解決辦法, 而且亂序插入會頻繁的觸發頁的分裂, 不光更耗費空間, 性能也會差一些, 所以你知道為什么DBA推薦使用遞增主鍵了吧?"
小張 : "對了, 我看最開始那個User表, name 是個輔助索引吧, 輔助索引怎么設計啊, 也是B+樹嘛"
老王 : "嗯, 也是B+樹, 但是葉子節點咱就別指向數據頁了, 直接指向主鍵, 也是就 id 吧"
小張 : "那查詢的時候不就需要先查輔助索引找到主鍵, 然后需要按照主鍵再查一遍了嗎"
老王 : "你別光想著查詢啊, 你別忘了我們這個設計是以主鍵id為維度的組織索引表, 看看我剛才畫的圖, 插入 id 為 2 的數據的時候是不是發生了頁的分裂, 從而導致 id 為 3 的數據被移動到了頁3? 我這里舉的例子一頁只有兩條數據還好, 按照正常情況一頁可能幾百甚至幾千條數據, 我去, 那頁一旦分裂, 還要把所有移動的數據的輔助索引指向的數據頁都改一遍, 那你可能最壞情況下插一條數據幾十秒, 這誰受得了啊"
小張 : "哦哦, 有道理, 文件結構我弄懂了, 接下來呢?"
老王 : "接下來還沒想好呢, 今兒先到這兒吧, 回頭我再想想, 走, 吃飯去!"
總結
以上是生活随笔為你收集整理的先查询再插入的存储过程怎么写_谈一谈 InnoDB(1) - 底层存储文件结构的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: html中alert的用法_【渗透实战】
- 下一篇: ipad写python_ipad怎么写p