SQL Server 2014 新特性——內存數據庫
目錄
簡介:
內存數據庫(In-Memory OLTP),代號Hekaton
設計目的和原因:
1.將請求的負荷放到內存中
2.減少數據延遲
3.來適應特殊的負荷類型
如果數據都是在內存中,那么當前的數據庫優化器產生的執行計划是沒什么意義的,因為現在的優化器默認數據在磁盤中而不是在內存中,所以不從磁盤中讀取數據,優化器應該使用新的執行計划和新的開銷算法。
In-Memory OLTP 減少了鎖等待問題,使用基於行版本來優化同步的控制,改善了寫入等待的延遲,寫入日志變少,寫入次數變少。
專業名詞
Memory-optimized tables(索引優化表):引入了新的結構,被加入到in-memory oltp的新表
Disk-Based tables(磁盤表):基礎磁盤存放的表,就是我們一直使用的表。
Natively complied(原生編譯)存儲過程:用於索引優化表的訪問,也可以使用tsql訪問,通過原生編譯存儲過程訪問速度會更快一點
嵌套事務:可以在優化表中使用,也可以在磁盤表中使用
interop:可以讓tsql訪問索引優化表
In-Memory OLTP不同之處
通過圖可以發現,原生編譯存儲過程只能使用在內存優化表上,而query interop用戶tsql訪問內存優化表的橋梁
內存優化表
1.內存優化表和硬盤表不同,不需要把數據從硬盤上讀取放入cache中,
2.checkpoint只是用戶恢復的目的
3.和硬盤表一樣,使用事務日志,當服務重啟后,使用checkpoint的文件和日志,對內存優化表進行重建
4.內存優化表可以通過選項來設置表的持久性:SCHEMA_ONLY只保存表的結構,不保存數據,當服務重啟后數據就會丟失
內存優化表的索引
1.內存優化表中的索引不再以btree方式存儲,而是以hash 表的方式
2.內存優化表必須有一個索引,並沒有堆表的概念
3.索引,不會被保存在文件或者事務日志,並會根據內存優化表的修改自動維護,在所有重啟時,根據表的文件和日志重建索引
並發能力的提升
1.以行版本的方式存儲表數據,修改數據時會請求鎖,但是在內存優化表中不會
2.雖然沒有寫入鎖,但是還是有等待比如log write,比硬盤表高效,寫入的日志少,速度快
和競爭對手相比幾點
1.內存表和硬盤表通過interop集成,有利於過渡
2.原生編譯存儲過程,效率高
3.hash索引,提高內存訪問效率
4.沒有page,不會出現page latch的等待
5.通過行版本實現,不需要lock和latch
Getting Start
內存數據庫的使用
創建數據庫
CREATE DATABASE HKDB
ON
PRIMARY(NAME = [HKDB_data],
FILENAME = 'Q:\data\HKDB_data.mdf', size=500MB),
FILEGROUP [SampleDB_mod_fg] CONTAINS MEMORY_OPTIMIZED_DATA
(NAME = [HKDB_mod_dir],
FILENAME = 'R:\data\HKDB_mod_dir'),
(NAME = [HKDB_mod_dir],
FILENAME = 'S:\data\HKDB_mod_dir')
LOG ON (name = [SampleDB_log], Filename='L:\log\HKDB_log.ldf', size=500MB)
COLLATE Latin1_General_100_BIN2;
在創建庫時需要制定 MEMORY_OPTIMIZED_DATA文件組,用來保存checkpoint和delta文件,
創建的數據庫只能使用BIN2排序規則,原生編譯存儲過程只能支持在這些規則上比較,排序,分組
添加MEMORY_OPTIMIZED_DATA到已有數據庫
ALTER DATABASE AdventureWorks2012 ADD FILEGROUP hk_mod CONTAINS MEMORY_OPTIMIZED_DATA;
GO
ALTER DATABASE AdventureWorks2012 ADD FILE (NAME='hk_mod', FILENAME='c:\data\hk_mod')
TO FILEGROUP hk_mod;
GO
創建表
CREATE TABLE T1 (
[Name] varchar(32) not null PRIMARY KEY NONCLUSTERED HASH WITH (BUCKET_COUNT = 1024),
[City] varchar(32) null,
[LastModified] datetime not null,
) WITH (MEMORY_OPTIMIZED = ON, DURABILITY = SCHEMA_AND_DATA);
1.創建內存優化表是需要注明,MEMORY_OPTIMIZED=ON,並設置持久性
2.bit,tinyint,smallint,int,bigint,money,smallmoney,float,real,datetime,smalldatetime,datetime2,date,time,numeric,decimal,char,varchar,nchar,nvarchar,sysname,binary,varbinary,uniqueidentifier
BLOB的數據類型都是不被支持的
3.有2個持久性選項:1.SCHEMA_AND_DATA持久化數據和結構,2.SCHEMA_ONLY只持久化結構
4.每個表至少有一個索引,會自動為主鍵約束創建索引,在創建索引是要指定hash索引的bucket_count
5.創建表后,內存數據庫引擎會自動加載用於DML的原生編譯存儲過程,像加載ddl一樣
6.SQL Server 自身不操作內存數據庫的數據,而是通過ddl來操作
7.內存數據庫的限制:1.沒有觸發器,2.沒有外鍵和check,3.沒有identity,4.沒有主鍵以外的唯一索引5.最大8個索引,包括主鍵索引,9.不能通過alter table修改表結構,索引沒有DDL,索引是和表一體的,作為表的一部分創建
存儲
行
內存優化表使用內存字節地址,來代替磁盤區塊地址,不想堆表,內存優化表的行並不是存放在一起的,而是通過一個標記,來指明是同一個索引
結構圖
每行分為,行頭和payload。
行頭有begints(行插入時間),endts(行刪除時間),stmtid(保存事務中的語句id),idxlinkcount(索引引用計數器,若為0,會被指向到垃圾回收器),最后面8個字節*索引個數,說明內存表的索引。
payload是數據區,包含key和所有其他列,所以hash索引都是覆蓋索引。
Hash索引
hash索引是一組指針,每個組中的單元叫做hash bucket,index key通過hash計算把所有相同的hash值用同一個指針。
當索引被創建的時候,必須制定bucket大小,大小必須大於表中會產生的bucket大小,每個bucket都是使用內存的,並且是2的整數次冪,若設置的太多不但不會提升性能,然后會在掃描的時候降低性能。
數據操作
通過維護一個內部事務id(時間戳)來確定一個事務可見的行版本。
有三個時間需要留意:
1.Commit/End Time 每個事務數據被修改的時間都稱為 Commit Time或者End Time
2.Valid Time 可用時間,由3部分組成,BeginTx(行版本插入時間),Endtx(行版本刪除時間),在之間的就是可用時間
3.Logical Read Time 讀時間可以是事務開始到現在的任何時間,只要行版本的可用時間可以覆蓋讀時間,那么行版本就是可讀的,對於讀提交之外的隔離級別讀取時間是事務的開始時間,對於讀提交讀取時間是語句的執行時間。
隔離級別
內存數據庫支持一下幾種隔離級別:
1.快照
2.可持續讀
3.串行
只有在自動提交事務里面才能支持讀提交隔離級別,顯式事務或者隱式提交事務都不支持讀提交隔離級別
當不訪問硬盤表的自動提交事務可以支持讀提交快照,當使用TSQL啟用快照隔離級別,不能訪問內存優化表,當使用TSQL使用串行隔離級別,要使用快照隔離級別訪問訪問內存優化表。
DML
刪除:刪除操作只會在endtx上寫入一個時間戳,表示數據是否活躍,任何活動中的事務要訪問這條數據,在時間戳范圍內,都要看是否在該記錄還是活躍。
插入/修改:修改操作時先插入后刪除,任何寫沖突的事務都會直接報錯,修改完成后,要開始檢查隔離級別,如果隔離級別不對,那么就回滾。任何修改都會被記入write set中,有個指針執行相關的行。
讀取:以讀取時間為時間點,讀取可以覆蓋讀取時間的行
驗證:因為內存數據庫沒有鎖,所以要使用驗證來保證一致性:
1.快照隔離級別,commit出錯,由2個以上插入同一個主鍵
2.可持續讀,讀取的行,在提交前被另外一個事務修改
3.串行,讀取可用行出錯,或者出現幻影,無法保證串行
TSQL支持
解釋型TSQL
通過interop可以使用tsql訪問內存優化表,性能比原生編譯存儲過程差,但是方便,易兼容。
不支持,truncate,merge,動態、鍵值游標,交叉數據庫查詢,交叉數據庫事務,連接服務器,鎖提示,READUNCOMMITTED,READCOMMITTED,READCOMMITTEDLOCK這幾個隔離界別的提示,內存表類型和變量不支持。
原生編譯存儲過程
優點:可以執行的更快,有不少的限制,如數據類型和排序規則,不能用於訪問硬盤表
缺點:兼容性差