在逝去的2016后半年,由于項目需要支持數(shù)據(jù)的快速更新和多用戶的高并發(fā)負載,我試水SQL Server 2016的In-Memory OLTP,創(chuàng)建內(nèi)存數(shù)據(jù)庫實現(xiàn)項目的負載需求,現(xiàn)在項目接近尾聲,系統(tǒng)運行穩(wěn)定,寫一篇博客,記錄一下使用內(nèi)存數(shù)據(jù)庫的經(jīng)驗。
SQL Server 2016的In-Memory OLTP,通俗地講,是內(nèi)存數(shù)據(jù)庫,使用內(nèi)存優(yōu)化表(Memory-Optimized Table,簡稱MOT)來實現(xiàn),MOT駐留在內(nèi)存中,使用 Hekaton 內(nèi)存數(shù)據(jù)庫引擎訪問。在查詢MOT時,只從內(nèi)存中讀取數(shù)據(jù)行,不會產(chǎn)生Disk IO消耗;在更新MOT時,數(shù)據(jù)的更新直接寫入到內(nèi)存中。內(nèi)存優(yōu)化表能夠在Disk上維護一個數(shù)據(jù)副本,該副本只用于持久化數(shù)據(jù),不用于數(shù)據(jù)讀寫操作。
在內(nèi)存數(shù)據(jù)庫中,不是所有的數(shù)據(jù)都需要存儲在內(nèi)存中,有些數(shù)據(jù)仍然能夠存儲在Disk上,硬盤表(Disk-Based Table,簡稱DBT)是傳統(tǒng)的表存儲結(jié)構(gòu),每個Page是8KB,在查詢和更新DBT時,產(chǎn)生Disk IO操作,將數(shù)據(jù)從Disk讀取到內(nèi)存,或者將數(shù)據(jù)更新異步寫入到Disk中。
內(nèi)存數(shù)據(jù)庫將原本存儲在Disk上的數(shù)據(jù),存儲在內(nèi)存中,利用內(nèi)存的高速訪問優(yōu)勢實現(xiàn)數(shù)據(jù)的快速查詢和更新,但是,內(nèi)存數(shù)據(jù)庫,不僅僅是存儲空間的變化,Hekaton 內(nèi)存數(shù)據(jù)庫訪問引擎實現(xiàn)本地編譯模塊(Natively compiled),交叉事務(Cross-Container Transaction)和查詢互操作(Query Interop):
本地編譯模塊:如果代碼模塊只訪問MOT,那么可以將該模塊定義為本地編譯模塊,SQL Server直接將TSQL腳本編譯成機器代碼;SQL Server 2016支持本地編譯的模式有:存儲過程(SP),觸發(fā)器(Trigger),標量值函數(shù)(Scalar Function)或內(nèi)嵌多語句函數(shù)(Inline Multi-Statement Function)。相比于解釋性(Interpreted)TSQL 模塊,機器代碼直接使用內(nèi)存地址,性能更高。
交叉事務:在解釋性TSQL模塊中,一個事務既能訪問硬盤表,也能訪問內(nèi)存優(yōu)化表;實際上,SQL Server創(chuàng)建了兩個事務,一個事務用于訪問硬盤表,一個事務用于訪問內(nèi)存優(yōu)化表,在DMV中,分別使用transaction_id 和 xtp_transaction_id 來標識。
查詢互操作:解釋性TSQL腳本能夠訪問內(nèi)存優(yōu)化表和硬盤表,本地編譯模塊只能訪問內(nèi)存優(yōu)化表。
內(nèi)存數(shù)據(jù)被整合到SQL Server關(guān)系引擎中,使用內(nèi)存數(shù)據(jù)庫時,客戶端應用程序甚至感受不到任何變化,DAL接口也不需要做任何修改。由于Query Interop的存在,任何解釋性TSQL腳本都能透明地訪問MOT,只是性能沒有本地編譯TSQL腳本性能高。在使用分布式事務訪問MOT時,必須設(shè)置合適的事務隔離級別,推薦使用Read Committed,如果發(fā)生MSSQLSERVER_41333 錯誤,說明產(chǎn)生交叉事務隔離錯誤(CROSS_CONTAINER_ISOLATION_FAILURE),原因是當前事務的隔離級別太高。
一,創(chuàng)建內(nèi)存數(shù)據(jù)庫
內(nèi)存優(yōu)化表的數(shù)據(jù)必須存儲在包含Memory_Optimized_Data