01 SQL Server 如何讀寫資料

2021-09-06 16:27:10 字數 3720 閱讀 6364

原文:

01. sql server 如何讀寫資料

一. 資料讀寫流程簡要

sql server作為乙個關係型資料庫,自然也維持了事務的acid特性,資料庫的讀寫衝突由事務隔離級別控制。無論有沒有顯示開啟事務,事務都是存在的。流程圖如下:

資料讀寫流程圖

0. 事務開始

(1) 所有dml語句必然是基於事務的,如果沒有顯式開啟事務,即手動寫下begin tran,sql server則把每條語句作為乙個事務,並自動提交事務。

也就是說sql server 預設不開啟隱式事務,這點與oracle正好相反,oracle預設開啟了隱式事務,每條dml語句或者語句塊,都要手動commit才會提交。

sql server裡如要改變這個預設行為,可以在會話裡做如下設定,如果沒有開啟隱式事務,sql server會自動提交當前的dml語句,而開啟後,需要手動commit才會提交。

--

開啟隱式事務

set implicit_transactions on

--插入一條記錄

create

table test_tran(id int

)insert

into test_tran values(1)--

檢視開啟的事務

dbcc opentran()

(2) 如果手動開啟了乙個事務(begin tran),則和開啟隱式事務(set implicit_transactions on)一樣,需要手動提交事務(commit);

1. 發起dml

(1) dml通常指的是:insert、delete、update;

(2) ddl語句最終是被轉化為對系統表的dml,在sql server中ddl語句也可以被回滾,比如:create/alter/drop/truncate,在oracle裡是不可以的,另外sql server中的dcl語句:deny,revoke,也可以被回滾;

2. 資料是否在記憶體

(1) 在記憶體中使用hash演算法查詢資料,如果找到資料那麼記為邏輯讀;

(2) 如果資料頁不在記憶體中,則需要從磁碟上的資料檔案中,讀取相應的資料頁到記憶體中,即物理讀,物理讀也會被記數為邏輯讀,也就是說無論記憶體中有沒有資料,邏輯讀是一定有的。

3. 修改資料

(1) 在sql server記憶體的資料緩衝區中將資料頁修改,此時資料頁稱為髒頁(dirty page);

(2) 在sql server記憶體的日誌緩衝區中記錄redo log,姑且稱為髒日誌;

4. 事務結束

(1) 提交(commit),此時將當前事務的髒日誌重新整理到資料庫的日誌檔案中,並打上事務結束標記(commit),髒頁有可能暫未被重新整理到資料檔案;

事務日誌結構如下(可通過log explorer等類似工具檢視):

begin tran

dmlcommit tran

(2) 回滾(rollback),此時讀redo log得到反向dml操作,反向修改髒頁,正向的dml+反向dml都會被記錄在資料庫的日誌檔案中,並打上事務結束標記(rollback),同樣,髒頁有可能暫未被重新整理到資料檔案;

事務日誌結構如下:

begin tran

dml反向dml

rollback tran

不難發現,sql server的日誌容易成為乙個瓶頸(bottleneck),因為在寫的同時引入了讀,即引入了競爭,而oracle用undo segment很好地避免了這個問題,redo log永遠只是在被序列寫。

5. 重新整理資料頁

(1) sql server資料庫遵循預寫日誌(wal:write-ahead logging)原則,因為關係型資料庫是基於事務的,而日誌正是事務acid屬性的保證,也是資料恢復的保證;

(2) 檢查點(checkpoint),檢查點周期性地將髒頁重新整理到資料檔案中,最終在日誌檔案打上檢查點標記(checkpoint),至此上面事務中修改的資料被正式寫到磁碟上的資料檔案中。

二. 資料讀寫流程深入

試想:(1) 日誌是不是一定要在commit後才寫到日誌檔案?如果有個很長很大的事務,那麼提交日誌時,日誌從緩衝區被寫入磁碟,豈不是要等很久?

(2) 資料是不是一定要在日誌提交後,發生了checkpoint,才寫到資料檔案?如果日誌一直沒提交,那麼資料緩衝區豈不是很擁擠?

考慮到這2點,sql server還會通過log writer/lazy writer不定時的重新整理日誌/資料到磁碟,至於日誌和資料的一致性,在啟動或者資料庫還原時,sql server會去做檢查,也即是我們常說的前滾(redo)和回滾(undo)。

資料讀寫體系結構圖

0. sql server memory

(1) sql server占用伺服器記憶體的一部分,非sql server占用的記憶體,供作業系統及伺服器上其他應用程式使用;

(2) sql server記憶體物件可分為兩大類,圖中僅標出buffer pool中的資料及日誌快取;

1. 事務結束

(1) 事務結束的前提是日誌快取成功寫入到日誌檔案中,也就是說客戶端收到commit/rollback語句執行成功的訊息時,日誌已被成功寫入日誌檔案(資料還不定是否被寫入資料檔案);

(2) 不過,日誌快取並不是一定要等到事務結束時才重新整理到日誌檔案的;

2. log writer

(1) 當遇到長事務時,不必等到發出事務結束命令,log writer也會周期性地將髒日誌重新整理到日誌檔案,以保證使用者發出commit時快速響應以結束事務;

(2) 微軟並沒有公布sql server 除去commit外,log writer將髒日誌重新整理到日誌檔案的週期,這裡可以參考oracle的:每3秒,或者日誌緩衝區1/3滿;或者已經包含1m的髒日誌;

3. lazy writer

(1) lazy writer週期性掃瞄快取(預設1s),維護自由頁面(free page)列表,根據lru演算法將已重新整理到磁碟的頁釋放;

(2) 如果是髒頁,則lazy writer將髒頁重新整理到磁碟(這時事務可能還未提交),以最終將記憶體頁釋放並加入自由頁面列表;

4. checkpoint

(1) checkpoint同lazy writer一樣也會重新整理髒頁到資料檔案中(只重新整理已提交的事務資料),但不會維護記憶體自由頁面列表;

(2) 可以設定sp_configure 『recovery interval』選項來改變checkpoint發生的頻率,預設為1分鐘一次。

小結:可以發現,資料和日誌被寫入資料/日誌檔案,並不是同步的。有可能寫入/提交了日誌,資料沒有寫入磁碟;有可能寫入了資料,事務未被提交;

(1) 針對有完整事務日誌,資料未被寫入磁碟的情況,啟動/還原資料庫時,sql server做前滾(redo);

(2) 針對有資料寫入資料檔案,日誌未完整提交的事務,啟動/還原資料庫時,sql server做回滾(undo)。

01 SQLServer版本代號和補丁

一 各個版本和補丁 官網最新更新資訊 二 版本代號 sql server發布版本 內部版本號 代號 sql server 2019 15aris sql server 2017 14helsinki sql server 201613無 sql server 2014 12hekaton sql s...

SQL Server和Access資料讀寫

1 查詢access中資料的方法 select from openrowset microsoft.jet.oledb.4.0 database c db2.mdb select from serv user 或select from opendatasource microsoft.jet.ole...

ADO讀寫SQlServer資料庫

寫入時間值 coledatetime oledate coledatetime getcurrenttime variant t vtfld vtfld.vt vt date vtfld.date oledate precordset4 putcollect date vtfld 讀時間值 bstr...