天天看點

DBA呢?我的資料庫又雙叒叕連不上了!

“工藤邦明先生似乎是個誠實可靠的人。和他結婚,你和美裡獲得幸福的幾率應該比較高。請把我完全忘記,千萬不要有罪惡感。因為如果你過得不幸福,我的行為将會完全成為徒勞。”——《嫌疑人x的獻身》

DBA呢?我的資料庫又雙叒叕連不上了!

看到這裡别慌,筆者寫這篇文章的目的不是為了想要跟你探讨關于這部電影裡的那些哲學命題:

拟一個别人無法解答的問題和解開這個問題,何者更困難? 

自己想出的答案和判斷别人的答案,何者更容易? 

隻是作為一個dba(逗b啊)随着對接項目的增多,難免會需要給相關的開發解答一些存在共性的資料庫問題。是以在筆者的從職生涯裡,關于故障處理有一些比較頭大的場景:

一類是那種你需要參考古老的dsi(oracle的技術内部文檔但很早就停止更新了)去進行推演驗證的,抑或使用場景極端,碰上了bug。

還有一類問題就比較尴尬了,比如開發找到你“我也不知道怎麼了,感覺環境有問題”。

朋友,你拟問題的時候是不是把我想像成了《嫌疑人x的獻身》裡的智商爆表的實體學家。生怕線索給多了,問題太簡單就給解決了就沒意思了,顯得我不厲害?

DBA呢?我的資料庫又雙叒叕連不上了!

用人話來比喻一下:一個病人得了腎結石,他到醫院看病,醫生問診的時候他雖然不用明确的告訴醫生他是由于腎結石導緻的腰部鈍痛,需要肌肉注射20mg黃體酮來擴張、松弛輸尿管平滑肌……

他不用清楚這個病的病理,也不用去了解黃體酮的藥理。他隻需要跟醫生描述病情的時候他能夠分得清他鈍痛的部位是腰,那裡不是腦袋,也不是手,不是胳膊不是腿。醫生隻要再問問他是不是伴有惡心,嘔吐的症狀。到這線索就明朗了,醫生再讓他去拍個b超到這基本就能确診了。當然自己的身體,我們看着他長大(這句話有點怪怪的),是以我們能夠分得清胳膊腦袋腿,這些關于生理構造的基本認知能夠很大程度的降低我們于醫生溝通是有效資訊傳遞的難度。

對于開發人員,但凡你需要将資料落地存儲于一個永久媒體以便你能複用這些資料,就永遠要跟資料庫打交道。是以,筆者亦希望通過這篇文章介紹一條sql的操作執行在oracle資料庫的曆程。能夠讓你能夠分得清資料庫的“腦袋”“胳膊”“腿”,讓你在跟dba打交道時少走些彎路。

DBA呢?我的資料庫又雙叒叕連不上了!

 dba哲學三問

我是誰,我在哪裡,我要去哪。人生三大命題,與你的人生一樣,一條sql其實也需要搞懂這三大哲學命題。

先從連接配接串下手:它決定了你連接配接的是哪個資料庫。不論是ide工具亦或者是sqlplus直接連接配接資料庫使用者名密碼之外連接配接串是必須填寫的。

192.xx.xx.1:1521/xxxserv 完整的oracle連接配接串就由這3部分組成:

目标機器ip位址 192.xx.xx.1

監聽工作端口(預設是1521,隻有少數的oracle資料庫環境會把監聽配置在其他端口)

oracle的服務名或(sidname) xxxserv。當然大部分會通過配置tnsname來簡化這個連結串的配置。

DBA呢?我的資料庫又雙叒叕連不上了!

(1)用戶端使用sql plus或odbc請求連接配接,監聽接受用戶端的tcp連接配接,并擷取用戶端發過來的tns資料包。

這一步容易出的問題有兩類:

比如用戶端的odbc驅動太老,或者oracle 的client沒有被正确安裝;

在網絡環境中預設的資料庫端口的1521 tcp協定被限制。

正常處理:用戶端測試,odbc測試,telnet網絡端口協定測試。

(2)監聽程序打開用于與子程序通信的管道,同時fork一個子程序,稱為“監聽子程序1”的子程序,然後監聽程序一直等待,直到這個“監聽子程序1”結束。

(3)監聽子程序1 fork出子程序2。

(4)完成上面一步,子程序1馬上退出并結束子程序1。

(5)子程序2收集本程序所在的主機名丶ip位址及程序号等資訊,并把子程序2重名成server process(這裡我們也把server process叫前台程序或叫伺服器程序),申請占用一小塊pga記憶體。

注:第二到第五步,oracle已經把這塊工作流封裝的很好很快了,幾乎不會出問題,但是到了第五步這裡,可能會由于oracle的運作參數process限制以及session限制導緻亦或者是pga完全耗盡(單個session占的pga記憶體資訊可以通過v$session,v$process_memory,v$process幾個性能管理視圖查詢擷取)。當然一般碰上這類問題,會有十分明顯的報錯,并且報錯很直接。

(6)前台程序把主機名丶ip位址及程序号發送給監聽程序。

(7)監聽程序收到前台程序的資訊,并傳回用戶端的資訊(比如使用者密碼環境變量等)給前台程序。

(8)前台程序查詢user$丶profile$等資料字典,校驗使用者名密碼是否合法,如果使用者密碼錯誤就報錯使用者名密碼無效,否則就與用戶端進行互動。

(9)用戶端收到前台程序的資訊與之互動,整個連接配接建立完成。

以上過程,用理發這個活動來解釋一下:

DBA呢?我的資料庫又雙叒叕連不上了!

我(client程式)需要到理發店(db 資料庫)找造型總監tony老師(建立連接配接後指定給client的會話資源)理發(資料操作即事務之後以一條update為例),我要完成理發這件事,我需要找到這家理發店(連接配接串即位址)。

但是我不是這家店的員工(client非dbservevice的背景程序),我需要到門口找到業務員(server端的1521監聽,負責監聽遠端連接配接client通過他完成與資料庫建立連接配接)。

關于理發這件事我可能會碰上如下情況:

這件店位址不對(即連接配接串無效)

我自身不能進這家理發店(client程式錯誤或者odbc驅動太成就有問題)

門口接待的業務員沒了(監聽程式未啟動,或db處于維護狀态dba将監聽關閉

份驗證失效(會員卡密碼忘了)

這家店太忙了,不論是tony老師還是peter老師都排滿了(session或者process達到db的配置允許上限,pga無法給client連接配接配置設定記憶體)

好了,用戶端跟資料庫的遠端連接配接已經建立,你可以開始執行sql了。

◆  ◆  ◆  ◆  ◆  

上面我們講到了用什麼樣的姿勢更好地接入資料庫,下面将介紹如何進行操作,上車!

連入資料庫,大家一緻認為,我跟你資料庫互動,你讓我資料落盤快,請求快就好了,找到資料落盤不是順理成章嗎?為什麼要引入undo什麼的這些亂起八糟的東西,明顯會讓響應變慢啊。

為什麼一條簡單的update,到oracle裡需要經過下面那麼多啰裡啰嗦的操作流程,這其實已經是資料庫設計人員在這麼多年以來得到的一個時間和空間,性能和備援的最佳“平衡點”。

其實,在計算機科學的1和0的世界裡,體系架構無非這幾件事:時間換空間,空間換時間,以及性能換備援,備援換性能。而這幾個基本問題最終都會觸及到現在的科學邊界,無法逾越。一個特性的優點,背後一定會有其對應的代價付出。

以下文即将提及的undo為例,提供一緻性讀(consistent read),復原事務(rollback transaction),執行個體恢複(instance recovery)這些特性因為其存在能夠得到很好很高效的支援。

同樣是oracle資料庫,如果用來跑一個耗時很長的統計報表,大概需要3個小時。在這個業務場景下你也許接受了時長好像并不是太大的問題,但跟人生很多事情一樣,你等得起,不代表就一定會得到結果。undo機制的問題碰到了ora-01555(快照過舊)引發了事務中斷,undo的機制在這種應用場景下反倒成了累贅。

這裡提一下滿足三範式的設計,對oltp事務類型業務能夠提供很快的支援,但一些資料倉庫以及資料集市的業務,為了獲得性能反倒往往是需要反三範式的設計。一般oracle(exedata等除外)的行資料存儲的方式,當需要進行整列的sum統計等操作時,相比列式存儲能夠得到的性能也是天差地别。

業務場景千變萬化,是以我們就以最簡單的一條update 來感受下資料到底在幹嘛。

DBA呢?我的資料庫又雙叒叕連不上了!

 update t_test set name='wahaha' where id=1

當連接配接會話完成建立之後,你将一條sql送出給db sever 接下來會發生什麼呢?他會來到oracle的librarychache:         

DBA呢?我的資料庫又雙叒叕連不上了!

(來自dsi405的library cache 示意圖)

oracle的記憶體體系結構最複雜的就是sharedpool,而shared pool中最複雜就是library cache,出于文章目的及篇幅所限,就不再繼續做詳細展開,簡單講講sql在裡面的運作流程。

第一會将sql(update t_test set name='wahaha' where id=1)的每個字元當然包括空格轉化成ascii碼後,再拿這一堆ascii碼通過hash函數生成一個sql_hash值,oracle拿着這個sql_hash值去描掃hash buckets(看上面的圖,這個幅畫的不太好,隻畫了0号的hash buckets),假如剛好sql_hash值=0,那麼oracle就延着0号hash buckets去搜尋object handle鍊,在這個object handle上存有sql的文本,如果和我們的update t_test set 

name='wahaha' where id=1一模一樣對上,那就說明這條sql已被緩存在共享池了,這個過程就是軟解析,最後執行計劃是被存放在heap 6中。

如果通過上面的方式在object handle鍊沒搜尋到這條sql的文本,則說明sql不在共享池中,這個時侯就要做硬解析(過程大要做文法,語義,權限,查詢視圖展開丶劃分小的查詢塊丶sql等價轉換丶代價估算丶最後生成執行計劃),這個代價會有點高,如果有大量的硬解析那會消耗cpu和占用共享池。

DBA呢?我的資料庫又雙叒叕連不上了!

人話版本:我的資料庫接收到你的一條sql,每天執行的sql那麼多,我也沒記住你是不是最近執行過了。我到sga的library cache緩存裡找找,看看還有沒有你上一次的sql資訊。當然我們的library cache呢 使用的是lru(最近最少使用淘汰算法)。如果sql是經常執行的,肯定能找到你的緩存的。

但是如果sql執行的次數較少,那麼很大機率在事務量繁忙的資料庫。哪怕執行了沒多久仍然有可能被 lru淘汰掉。是以如果sql不在,就需要消耗一定的cpu以及記憶體資源來完成sql語句的解析才生成并存放sql的執行計劃。在sga配置的較小但是有大量sql解析的db環境中,極有可能碰上library cache不足以及大量的硬解析并發導緻cpu的使用率飙升的情況。

更極端一點的,在一個并發很大的oracle線上生産系統,在業務繁忙的階段進行權限的revoke操作,也會導緻這個表的相關sql會被 aged out,引發解析風暴。同樣的,在你删除或變更一張核心表的索引的時候,雖然最主要的風險還是執行計劃的變更導緻sql執行率下降進而導緻cpu記憶體被占用。但是哪怕索引删除變更後sql執行效率沒有太大波動,但是shared_pool 中的與這個表相關的sql 都會被aged out,必須重新分析,這個帶的風險在并發壓力大的資料庫系統中也要被考慮進去。

我們再往下看的話涉及到就是oracle資料庫是如何undo,和redo在保障acid的事務特性下,盡可能的把并發以及執行效率提升的原理(以update為例),涉及專有名詞太多,筆者說人話也不好解釋。 ╮(╯▽╰)╭

1、如果id列上無索引

查詢seg$等資料字典,找到test表段頭

從段頭讀出extent map,開始全掃描

找到第一個滿足條件的行,進行修改

查找同一塊中剩下的行,先構造一個cr塊,在cr塊中繼續查找,如果又找到滿足條件的行,在xcur塊中修改

2、如果id列上有索引,且版本不是11gr1(10g丶11gr2),則不需要構造cr塊

通過索引找到目标資料塊。

3、id列無論是否有索引,在11gr1下都需要構造cr塊

4、如果name列上有索引,增加索引維護步驟:

先在原索引塊中删除要修改的原值

再将新值插入

5、任何塊的修改,都有以下步驟(非imu)

在pga中生成undo段頭事務表的後映像(5.2)

在pga中生成undo塊的後映像(5.1)

在pga中生成datablock塊的後映像(11.9)

将前三個redo矢量做為一條redo recorder寫入log buffer

修改undo段頭的事務表,事務正式開始。

修改undo塊,寫入datablock的前映像。

修改datablock,将新值“wahaha”寫入buffer cache

6、任何塊的修改,都有以下步驟(imu)

将前三個redo矢量做為一條redo recorder寫入shared pool中的private strand

将datablock中的前映像值,寫入shared pool中的imu pool

修改undo段頭的事務表

修改undo塊,寫入datablock的前映像

DBA呢?我的資料庫又雙叒叕連不上了!

 commit

1、非imu下(按最常見的快速送出):

在pga中生成commit的redo 資訊(編号5.4),另做為一條redo recorder,寫入log buffer

修改事務表相應slot,聲明事務已送出

修改datablock,在itl slot中寫入快速送出标志和scn。每行上的行鎖不清0

通知lgwr,将log buffer寫入redo file

收到lgwr通知,寫入完成

向使用者發收送出完成資訊

2、imu下(按最常見的快速送出)

在pga中生成commit的redo 資訊(編号5.4),傳入shared pool中的private strand,追加在事務之前的redo recorder之後

将private strand中的redo資料寫入log buffer

DBA呢?我的資料庫又雙叒叕連不上了!

 exit

斷開連接配接,中止伺服器程序,釋放pga。

補充一下,任何不結合業務場景,一味鼓吹xx技術是最好的技術的人,大部分情況下并不是因為他們是傻子,他們隻是把你當傻子。而且洗腦的發生,有時候是靜悄悄的。

至此你的一條update 完成了他與資料庫互動的一生。

作者介紹 崔霄

目前就職于點融網infra團隊,dba一枚。喜歡徒步、開車。

原文釋出時間為:2016-12-28

本文來自雲栖社群合作夥伴dbaplus