[toc]
數據庫作業
存儲技術
在數據庫中,在數據存儲方面,一般分為定長,和變長,兩種方式。采用定長存儲的時候,每條記錄分配的長度是固定。不論記錄的內容,是否使用完分配的地址,都采用固定的空間。采用變長存儲,每條記錄分配的地址長度不是固定,很多時候,分配的都是記錄實際存儲位置的,一個地址,在查找的過程中,根據地址找到實際的數據位置。
針對變長,和定長,的優缺點,我自己歸納如下:
定長:
優點:
- 策略簡單,程序實現方便,不需要過多的維護指針的地址內容。如果是相鄰存儲。所有地址,都有可能通過直接計算得出地址。(實際上,在實現作業三的時候,采用的就是定長地址)。
- 方便批量順序讀取,大數量讀取的時候,效率高。
- 數據集中,不易產生碎片
缺點:
-
空間浪費,如果當字段大部分記錄長度短。其中有某一個記錄的長度很大,按定長存儲策略,就會造成空間很大的浪費:
例如:我在實現作業三的過程中,曾經創建過這樣一個shcema的數據表['int', 'text(6)', 'text(50)', 'int']。在第三個text字段,我采用分配50個字節記錄。生成1w條數據的時候,大約占用內存700多kb(而不是680k,因為用了,分塊存儲,1K數據一塊,為了對齊,中間有些空間,為空)。但是,采用['int', 'text(6)', 'text(500)', 'int']這樣的schema,第三個text字段采用500個字節,同樣是1w的數據量,大約占用內存19.1M。如下圖:
數據占用內存的截圖 對于極大的字段內存空間節約會更理想。例如有些數據庫字段存放電影。有些記錄,是2G的電影內容,有些是電影的標題,如果采用變長字段,將會極大的減少數據庫的大小
變長:
優點:
- 節省空間,特別是在記錄,長度不一的時候,刪除修改方便。(只需要修改,或標記該地址為空閑)
缺點:
- 程序實現復雜,維護記錄地址,需要小心
- 對于跨塊記錄存儲的記錄,要小心。
- 數據不集中,讀取數據局部性不高,影響i/o效率
變長記錄,在部分商業數據庫中的應用
sqlite 應用變長記錄
sqlite定位為嵌入式數據庫,因此在數據庫空間大小上,要求更嚴格,因此采用變長記錄更為合理,更符合產品定位
在sqlite的官網文檔中,提供,vacuum,命令,用于在刪除大量記錄之后,手動釋放sqlite空閑空間使得數據庫文件壓縮到最小
由于sqlite采用的是變長存儲。在大量插入數據的時候,數據庫空間,會自發增長,當在原有數據庫中大量刪除數據時,就會有大量的存儲空間,被標為空閑,如果后面再插入數據,優先在這些空閑塊中插入數據。
這就存在一個問題,sqlite數據庫,會只增加,不縮小。vacuum命令,就提供一種手動是否空閑空間的工具,使得空間壓縮到最小。
MongoDB MMAPV1引擎應用定長記錄
這一部分,沒有做實驗,資料來源于閱讀MogoDB官方文檔
MogoDB,定位為 Nosql 數據庫。屬于文檔型數據庫,在OLAP,和OLTP上都有應用。其中MMAPV1 (Mobile Messaging Access Protocol) 存儲引擎是原聲引擎,官網文檔,定義如下
`MMAPv1 is MongoDB’s original storage engine based on memory mapped files. It excels at workloads with high volume inserts, reads, and in-place updates.`
之所以,提供高新能的插入,讀取,和原地修改,與MMAPV1引擎的數據存儲策略有關。在MMAPV1引擎中,所有數據,相鄰存儲,初始空間分配大小為2倍(2 size of Allocation)分配空間的時候盡量是2的倍數空間大小。小于2M的數據,按數據量的2倍分配。大于2M數據,按2M的倍數分配。(如14.1M數據,會分配16M的空間)這樣帶來的好處是,充分利用空間,做到跟操作系統地址對齊,讀取效率更高。同時,2 size of Allocation
策略,也能使得數據在修改的時候,盡可能的保證, high volume inserts, reads, and in-place updates.
在mogoDB中,如果是采用MogoDB作為OLAP數據倉庫,么么針對,一些不常修改的數據,可以采用full fit策略,這樣能使得數據實際大小和占用空間大小,盡可能的接近,這種策略能最大程度上使用磁盤。
不論是定長存儲,還是變長存儲。都要針對特定的數據庫產品,采用特定的策略
索引技術
在絕大部分數據管理系統中,都會應用到索引技術,來加快,數據查找的效率,其中索引,分類有稠密索引,和稀疏索引。種類,有,B樹索引,哈希索引,R-樹索引,kd-樹索引等。在mysql中,默認的建立索引的方式為B樹索引,所以我主要了解,只有B樹索引:
實際的產品數據庫中,數據量大的時候大多采用多級索引,即,在索引上,再建索引,上層索引一定是稀疏索引
索引技術在mysql中幫助提高查詢效率
info_schema
表,為mysql優化提供了很多有用的信息
show create table titles 查看表結構,和索引細節
這次實驗,采用的是mysql中官方發布的employees數據庫,employee表結構如下圖
titles 表的數據量:
通過,
showcreate table titles
show inidex from titles
,可以看出這張表的結構信息,通過explain 子句,可以查看這個查詢使用索引的情況,如下圖
通過輸出信息,了解到表之后,一個3個字段的多列索引。輸出的rows字段,為442308,表明在where條件上的select查詢語句,用到的策略是全表掃描,
myssql 添加索引,及不添加索引,前后效率效果比對
如果在表上加上索引,rows預計需要掃描的行數量,就縮減為69行。能大大加快表的查詢
創建數據庫索引,注意事項
數據庫索引,確實能在生產環境中給數據查詢帶來很大的效率提升。大部分時候帶來的提升,可能會有幾倍,或者幾十倍的效率提升空間。但是并不是所有時候都適合創建索引
比如。如果數據庫的量比較大,往往在新建索引的時候可能會花費幾十分鐘,甚至是幾個小時,而在創建索引的過程中,數據庫是阻塞的。這個時候所有的請求都會等待,這在實際的生產環境中,很可能是不被容許的。
除此之外,如果會在一張表上,創建多個索引的話,如果在一個sql語句中創建多個索引,會比每個sql語句創建一個sql語句效率來的更高。時間有時候能縮短為幾分之一 。
在表中插入索引,的確能給數據庫的查詢帶來很大的提升,但是同時在數據進行插入的時候,對索引的維護,也需要一些代價,因此在實際生產的環境中,平衡讀取和寫入數據的時間,合理利用索引技術也是必須要注意的技能
EXPLAIN語法各列字段的意義:
-
key
: 優化器,使用的索引 -
rows
: 估計結果行數 -
possible_keys
: 可能用到的索引,可以通過show indexes 來查看表格 -
ref
:用來比較的列,或者常量 -
type
:const表示只有一行結果。ref,表示具有匹配的索引,都會被用到 -
select_type
: simple表示簡單查詢 derived 表示查詢的表,不是一個物理表,比如,在子查詢中再查詢。 -
table
: 用到的表格 -
key_len
: 索引,結構長度 -
filtered
:返回結果的行占需要讀到的行
sql優化的工作流
- 截取sql語句
- 識別出分類有問題的sql語句
- 確認sql語句的操作
- 分析sql語句和輔助信息
- 優化sql語句
- 驗證優化的結果
從mysql中截取sql語句的方法,有全面查詢日志,慢查詢日志,進程列表這幾個方法全面查詢日志,和慢查詢日志,主要通過設置mysql數據庫的設置選項,其中全面查詢日志,可以在前期數據庫不太大的情況下使用,但是在生產環境下使用會嚴重影響到數據庫的性能。慢查詢日志通過記錄數據庫中查詢時間超過某個閥值的時候,記錄下查詢信息,其中日志信息包括很多數據,通過日志可以了解到,語句執行頻率,來源用戶以及主機。等個得到的執行時間,處理過的行,以及結果集的大小。的最小,最大,平均以及中間值的統計信息。同事也有一些開源的工具,能對日志文件進行分析。
當從日志文件中分析出需要優化的sql語句止嘔胡,就可用通過上面EXPLAIN 語法查看具體sql的執行計劃,和表格上現在所擁有的一些索引信息,已經字段長度等等,通過查看具體的EQP,創建合適的索引進行查詢優化。
在優化了查詢語句之后,需要在實際的數據中驗證優化效果。最后應用到生產環境中去。
mysql 中的join算法
mysql 默認的采用的是簡單嵌套查詢,基于的實際假設是:數據庫表大小,都能完全放入機器內存當中。
我設計了一個實驗,讓myslq,對一個129M 和1.7G的數據進行鏈接(不超過內存,機器內存16G大小),建立約束條件。查看myssql實際的io數量。實際的數據大小,和數據內容如下:兩個數據集大小
數據集一字段內容
數據集二字段內容
給兩個數據集創建外鍵約束,在創建約束過程中,會使用連接算法
用iostat這個工具,監控磁盤io數據輸出。輸出的結果如下下圖所示:
工具輸出的數據,是以累計值,數據,所以兩者差額,約為7.2G,7.2G/1.5的數據,大約為5得出的io統計量為5倍io
從上面的結果來看,在建立外鍵約束,之后,查詢的效率就高很多能在0.0072秒只能返回查詢結果
NewSQL系統的一些技術
內存查找結構,skip-list
skiplist介紹
Skip List 是一種隨機化的數據結構,基于并聯的鏈表,其效率可比擬于二叉查找樹(對于大多數操作需要 O(log n) 平均時間)。基本上,跳躍列表是對有序的鏈表增加上附加的前進鏈接,增加是以隨機化的方式進行的,所以在列表中的查找可以快速的跳過部分列表 (因此得名)。所有操作都以對數隨機化的時間進行。Skip List 可以很好解決有序鏈表查找特定值的困難。
一個跳表,應該具有以下特征:
- 一個跳表應該有幾個層(level)組成;
- 跳表的第一層包含所有的元素;
- 每一層都是一個有序的鏈表;
- 如果元素 x 出現在第 i 層,則所有比 i 小的層都包含 x;
- 第 i 層的元素通過一個 down 指針指向下一層擁有相同值的元素;
- 在每一層中,-1 和 1 兩個元素都出現 (分別表示 INT_MIN 和 INT_MAX);
- Top 指針指向最高層的第一個元素。
就像這張表的結構
Skip List 構造步驟:
- 給定一個有序的鏈表。
- 選擇連表中最大和最小的元素,然后從其他元素中按照一定算法(隨機)隨即選出一些元素,將這些元素組成有序鏈表。這個新的鏈表稱為一層,原鏈表稱為其下一層。
- 為剛選出的每個元素添加一個指針域,這個指針指向下一層中值同自己相等的元素。Top 指針指向該層首元素
- 重復 2、3 步,直到不再能選擇出除最大最小元素以外的元素
skip-list 和二叉樹中的比較
如果單純比較性能,跳躍表和二叉樹可以說相差不大,但是加上并發的環境就不一樣了,
如果要更新數據,跳躍表需要更新的部分就比較少,鎖的東西也就比較少,所以不同線程爭鎖的代價就相對少了,
而二叉樹有個平衡的過程,牽涉到大量的節點,爭鎖的代價也就相對較高了。性能也就不如前者了。
在并發環境下skiplist有另外一個優勢,二叉樹在插入和刪除的時候可能需要做一些rebalance的操作,這樣的操作可能會涉及到整個樹的其他部分,
而skiplist的操作顯然更加局部性一些,鎖需要盯住的節點更少,因此在這樣的情況下性能好一些。
高并發,采用的 replica set技術
采用 quoram 機制+守護進程(即保證冗余又能保證數據庫最終一致性,來源于鴿巢原理),保證寫入的時候,不完全更新所有數據,但又在返回的時候保證返回給用戶的數據是有效的
mogodb中使用replica set 技術,在分布式的情況下,把主機分為primary 和seccondprimary對外提供接口服務,當一個寫入請求發送到primary中,primary節點,對請求進行解析,之后再分發給相應的second節點,各個節點通過定時發送heart beat進行同步。
其中quoram 機制,是保證高并發,和數據一致性的一個重要的機制。假如:當一份數據在分布式集群中,有存有三份,當寫入數據的時候,不需要三份數據都要修改,只需要修改兩份數據。當下一個讀請求來的時候,只需要讀取兩份數據,在這兩份數據中,一定存在至少一份數據是修改之后的數據。當這個原理推廣到數據有N份冗余的時候,只需要在數據中,寫入K個數據,當讀的時候,讀取N—K+1份數據的時候,那么必定至少有一份數據是更新后的數據。quoram機制,既能保證不完全更新,又能保證返回給用戶的數據是有效的。
對MogoDB的自問自答
為什么在已經有mysql這種數據庫的情況下,還會出現MogoDB這樣的數據庫?
- MogoDB支持高并發------>mvvc,quoram等。而mysql在單節點上比較適合,當并發連接數量大了之后,性能就跟不上
- 不需要大表連接 ------->mysql 大表連接性能差。在MogoDB中數據是noschema的并以文檔的形式存儲。這樣就能盡可能的減少表連接操作提高相應速度
- 可擴展--------->MogoDB既能橫向擴展又能縱向擴展上,當10臺機器,解決不了的時候,可以橫向擴展。加到100臺,1000臺,也許整體執行效率不高,但是能合作解決以往傳統數據解決不了的大數據量問題
- 對于OLAP,aggregation操作,進行優化,提供了自己的語言來支持更高效率的map reduce操作。并且對json,sql都有比較好的支持
- 同時提供full text search 和地理位置索引有很好的支持,這些在傳統的面向對象的數據庫中通常很弱
針對硬件發展優化的技術
memsql,meesql數據庫的口號是sreaming transations analytics all in one system.針對流數據進行一站式開發
memsql是一種內存數據庫。傳統數據庫,disk做主存,rammemory,做cache。memsql把memory作為主存。disk作為backup,或者journal使用,因為針對流數據,優化,所有數據只做順序讀寫。充分利用存儲金字塔。充分利用硬件,加快計算效率。在內存中,memsql采用行存儲,并采用想skip-lists和hashtable這樣的針對內存計算優化的數據結構加快計算。在disk中采用列存儲結構。更高效的存儲數據
而且memsql的驅動,與mysql完全兼容,針對程序員是透明的這一點在降低開發門檻很有效果。雖然memsql是一種內存數據庫,但memsql在斷電的時候,并不會丟失所有的數據,因為memory是主存,disk做backup和journal。在斷電的時候任然能通過journal找回數據。是一種針對通用硬件,同事支持企業級應用的高性能內存數據庫。支持完全的SQL
同事memsql可以設置持久化,并能很好的與spark等高性能計算平臺進行集成成為實時計算的一種較好的選擇
但memsql也有不適合的應用場景
- memsql 不適合存儲對象
- 不適合低端硬件。官網建議最低的硬件 4core 8GB
- 不適合作為共享DB(單節點安裝)
- 不適合作全文檢索
memsql 自問自答
為什么有了mysql MogoDB 之后,還有memsql這款產品
- 針對的應用場景不同,memsql針對流計算,更傾向與實時高性能計算,mysql,MogoDB更傾向與事務或者實時性要求不高的計算任務
- 針對高性能計算采取了多種優化,如內存行存儲。disk列存儲。應用skip-list,hashtable等加快計算
- 能與spark進行集成
- 完全的SQL,能通過code genarationg加快,sql的運行
memsql與傳統數據庫相比,有什么優勢
- 可擴展,集成。能與spark深度集成
- 基于流,無buffer pool (傳統表數據庫,在處理大數據量時候,假設不能完全放入內存中,內存設置buffer pool由DB和table共享,會產生競爭。導致爭奪)
- 采用lock-free技術最大化實現并發,用skip lists,或者hash table優化內存數據
- code-genaration。lock-free技術的使用,使得解析動態sql的時候成為限制因素。所以對sql語句進行預編譯。加快數據庫運行。
數據庫技術發展感悟
在今年上半年,看過的一篇文章《what comes around goes around》過去經歷的,將來也會再一次到來。數據庫,從最開始的樹型結構,網狀結構,星型結構,再到現在廣泛使用的表結構。現在在大數據時代,于是,又出現了一些,例如MogoDB,這些文檔型數據庫。無疑感覺是一種輪回。
在數據庫技術發展的歷史過程中,我認為經歷了這樣的一些過程
- 數據量大---》機器性能相對弱----》優先考慮性能
- 程序員管理,苦不堪言----》性能低下
- 機器性能提升,數據壓力減小------》優先考慮程序員
- 關系型數據庫----》管理技術趨于統一-------》一統天下
- 回到第一步
回顧數據庫技術發展歷史,數據從最初版本的用文件系統管理。然后出現了數據量大,使用文件系統管理效率太低,而且機器的性能這個時候又不夠,這個時候考慮的是如何在有限的硬件條件下,如何把不能解決的問題嘗試去解決。優先能不能處理的問題。就在這一時期,出現了樹狀結構,網狀結構,星型結構。效率高了,以前不能解決的現在能夠解決了。這是第一個階段
第二個階段。雖然數據是能解決了。但是隨著數據管理技術的結構設計讓程序員管理手動查詢這個時候,對之前存在的遺留代碼的管理操作。讓后來的從業者苦不堪言。而且,最重要的是不同程度技術的程序員,寫出的程序效率相差很大。這個時候,就會呼吁把數據管理,交給系統解放一部分程序員。
第三個階段,隨著機器性能的提升,計算機的廣泛應用,越來越多的IT技術從業者。強烈要求妥協一部分性能。讓廣大普通程序員也能寫出性能效率良好的管理工具,這個時候,出現了基于關系運算的數據處理技術,出現了給廣大程序員提供一個統一的接口,而不用考慮數據庫內部的運行過程。
第四各階段,在這個時候。機器性能的提升,新理論的出現。利用機器性能提升的特點。關系型數據庫似乎出現了一統天下的局面。之后,就是關系型數據庫的廣泛應用
第五個階段。隨著數據庫越來越廣泛的應用。數據積累的速度,也成指數性增長。于是又出現了類似第一階段出現的問題,數據量大,機器性能相對弱
數據庫技術,有10年理論,10年發展,10年應用的說法。我們現在所處的位置,似乎又回到了最初的數據量大,機器弱,優先考慮性能的這個階段。觀察,有些大數據管理系統如MogoDB,優先考慮性能,如,它會給用戶暴露特定的針對MogoDB特有的編程規范,來加速系統的運行。這就類似于程序員手動管理。
這是一種,用人力,換取效率的過程。帶來的提升就是,以往不能解決的問題,現在能夠解決了。但是不久就會出現,維護不變,市場需求量大。廣大程序員需要一種,效率不那么極致,但是能解決大部分問題的管理技術。未來,數據庫管理技術,會逐漸從零散到統一。從少量使用,到大量使用,最后又出現性能不夠處理的情況。
每一個輪回都是一次管理技術的提升。每一次硬件的效率提升,都會帶來新一次的變革。有的變革是理論驅動。有的變革,是硬件技術上的提升