您好,登錄后才能下訂單哦!
本文根據楊廷琨2018年5月11日在【第九屆中國數據庫技術大會】上的演講內容整理而成。
講師介紹:
楊廷琨,高級咨詢顧問, ITPUB Oracle 數據庫管理版版主 ,人稱“楊長老”,十數年如一日堅持進行Oracle技術研究與寫作,號稱“Oracle的百科全書”。迄今已經在自己的博客上發表了超過3000篇技術文章。2010年,與 Eygle 共同主編出版了《Oracle DBA手記》一書,2007年被 Oracle 公司授予ACE 稱號。
分享大綱:
·分區基本概念
·分區演進歷史
·分區最佳實踐
·分區最新特性
正文演講:
很高興,又和大家重聚在DTCC 2018的數據庫性能優化專場。這次我想和大家分享與分區相關的優化特性,主要會和大家介紹一些Oracle最新的分區技術以及我們在日常運營中的最佳實踐。
一.分區基本概念
Oracle對于分區的定義是根據內部定義的規則,將一張表的數據拆分到多個數據段中。分區之后,每個分區都是獨立的數據段。Oracle分區的最大好處是透明性,應用無需了解底層數據,訪問方式也與之前無異。換句話說,當把表做成分區表之后,程序不做任何的修改調整就可以直接跑,同樣如果把分區表改回普通表,也不要做任何調整。但是,這并不意味著做了應用之后我們就不需要了解表是否進行了分區。如果你想要分區帶來額外的性能好處,那么分區策略一定是要和應用程序、業務訪問方式相結合。
Oracle提供了幾種分區的訪問方式,最常用直觀的方式是通過分區擴展語句直接指定到某個分區。但我們不推薦這種方式,我們更推薦的方式是通過真正控制訪問數據、增加規范條件,讓Oracle幫你定位到需要訪問的某些數據。
分區的好處是什么?原來所有的操作都是基于一張大表去做的,而分區之后,一張大表化成了多個小單元,我們可以基于這種小單元去做刪除、截斷、遷移、索引等操作,分區提供了很好的細粒度操作手段。
提到分區,很多人第一反應是它帶來的性能優勢,但其實我認為分區最大的優勢是在可管理性和可維護性方面,管理很多小表或者小數據段的成本要遠低于管理一張大表,而且平均維護時間也會變少,但速度卻會更快。
第二個好處是可用性的增強,這也是Oracle官方宣稱的好處。原來,如果一張表對應的某個數據文件出現問題,影響的是整個全表,但現在可能影響的只是其中一個分區,因為它在邏輯上是相隔離的。
基于以上兩點,我們才能開始講性能的提升。在早期的版本中,Oracle只是直接說性能有一定提升,但其實這種說法是不準確的,因為分區如果設計不好,你的性能是會下降的。后來Oracle自身也意識到了,所以從Oracle 11版本之后,Oracle就把性能拆成了OLTP和OLAP兩種不同的情況去考慮。
OLTP處理的更多的是短時間內的大量并發,所以這時分區能帶來的好處是降低共享資源的爭用,消除熱點塊;OLAP面臨的是海量數據的處理,所以我們要更好的利用并行來提升性能。
二.Oracle分區演進歷史
Oracle最早是從版本 8引進分區的,上圖這張表給大家列出了各個版本的分區功能,并通過功能、性能和管理性三個角度解讀。很多人雖然在用分區,但是據我了解他們應用的很多特性都還集中在8、9版本,例如常用的范圍分區、歷史分區、列表分區等等功能。但其實之后的版本中,Oracle一直都有很多更好更新的功能提供給我們。
Oracle 12和18c中新增了很多非常實用的新功能,極大的簡化了大家的日常操作,接下來我會著重為大家介紹這些功能。
三.分區最佳實踐
接下來,我們介紹一下分區的最佳使用場景。
范圍分區的最佳使用場景是針對具有天然時間屬性的數據。例如,系統里記錄的訂單時間、生成時間、啟動時間等等。當然并不是只要有時間屬性數據就可以用范圍分區,還要看業務對時間是否有可見性的要求。另外,業務如果更關心近期數據就再好不過了,這樣范圍分區對性能提升以及過期歷史數據清理都會是很好的幫助。
隨著數據的不斷積累,我們都會擔心數據庫越來越大。如果業務對于數據的生命周期有明確要求的話,那么我們可以通過清理數據來讓現有系統維持在一個相對穩定的狀態。
如何去清理數據呢?傳統的Delete數據清理會面臨很多問題,例如效率低下、無法釋放空間等等。但如果我們的數據存儲有一個明確的時間限定條件,那么分區就是一個很好的選擇。
分區的清理成本和速度都很值得期待。在清理數據時,我們建議盡可能建立全局索引。數據清除操作是會影響全局索引的使用度,甚至導致索引失效。但如果我們是定期做分區數據清理的話,那么就不會影響全局索引的作用。
范圍分區的好處是什么呢?首先,數據分布是相對平均的,因為是按照時間等分的,數量也是可控的;通過DDL清理數據的速度很快,不會產生大量redo、undo的問題。同時,在設計時還要考慮盡量讓一個查詢集中在一個分區中完成,提升查詢效率。通過定期DDL方式清理分區,可以保證分區、表的大小維持在穩定的量級,同時索引也不會隨著時間迅速增長。
剛才我們介紹了范圍分區是最常用的清理過期數據的方式,但是在真正的產品環境中,我們會面臨各種不同的場景。例如,我們不能把所有數據都簡單的刪掉,因為刪除的數據中可能有少量的數據是需要保留的。
面對這樣的場景,如果使用Delete方式去刪除,你會發現雖然我們使用了分區,但是卻沒有享受到分區的好處。而且數據清理使用了原來的方式,那么必然會碰到原來的問題。
那我們有沒有更好的解決辦法呢?我們可以用Insert+Exchange的方式來做,我先把這部分數據從表中刪掉,如果這其中有少量需要的數據,再插回來就可以了。這種方式既保證了效率,也避免了遇到之前的問題。
上圖是我通過代碼簡單的給大家演示一下整個過程。
這里有一張T_PART表和P(3)分區,假設這其中有七八千條數據都是不重要的,但其中可能需要保留30條數據,那么我就會采用之前提到的Insert+Exchange方式。這里還有一個小竅門,我們是先Insert,再Exchange。為什么這樣做,如果這張表一致性非常重要,我們就要在操作之前,先把這張表鎖起來,避免別人對它進行操作,然后把需要保留的數據Insert到一張臨時表中,之后再去做Exchange。通過這種方式我們可以時刻保持數據的一致性。
除了上面的挑戰,我們可能還會面臨主子表的挑戰。假設我的主表和子表都做了分區,那我們可能會面臨以下挑戰,首先子表可能不存在主表的分區時間列,例如,有訂單表和訂單詳細表兩個表,并且兩者是主子表關系。其中訂單表是以訂單時間來分區的,這時訂單詳細表的分區時間列就會產生爭議,如果是按照訂單明細的創建時間,那么它和訂單時間可能是不一致的,且二者本身就是一對多的關系,所以在數據清理的時候,可能主表清理不了,如果要用訂單時間去分區,那么你就需要在表中冗余訂單時間。
如果只是冗余訂單時間,相信很多人都是可以接受的,但是挑戰還不止于此,一旦有了外健約束,主表無法執行truncate操作,必須先將約束disable掉,給運維增加很多不便。
如何解決這個問題?Oracle 11g就給我們提供了一個新功能叫參考分區,它是這么解決的:主表的字段還是按照主表時間列去分區,但子表不再需要冗余主表字段,而是直接依賴與主表的主外鍵關系去做分區。
參考分區適用于主子表建立相同的數據策略,同時子表沒有合適的分區字段,且主子表經常關聯訪問的場景。另外,Oracle 12還對此做了增強,支持級聯,換句話說,當我有主子表的情況時,不用先去子表做truncate,直接在主表做truncate,它就會遞歸的把所有子表truncate。
哈希分區相對來說比較簡單,它的適用場景是沒有時間屬性、缺少區分數據的業務字段的場景。如果系統面臨著共享資源的爭用,也可以使用哈希分區。
我建議哈希分區鍵值列盡量選擇重復度不高的字段,這樣不容易導致數據分布不均;分區數量最好是2的冪次方,這也是為了避免分區數量分布不均;針對沒有時間屬性和明確業務屬性的表,通常不會去做定期清理的策略,我更建議使用全局索引;另外,哈希分區索引可以有效的解決索引熱點塊的問題。
有人可能會有這樣的疑問,既然我的數據沒有業務特點,為什么要分區呢?我們之前碰到過這樣一個案例,客戶的表量級非常大,400T的數據可能有395T的數據都在同一張表中 ,客戶面臨的問題是表可能存不下這么多數據,Oracle對于表容量沒有限制,但是對于表空間的容量是有限制的,這時你會發現如果不用分區,這個問題就是無解的。
哈希分區可以解決的一個問題是熱點塊問題。為什么會產生熱點塊問題呢?對于OLTP系統來說,會有大量的數據插入。插入數據的類型一般有兩種,一種是主鍵,另一種是時間類。這兩組數據的共同點是新插的數據永遠是最大的,當多人同時做插入時,因為表是無序的,所以沒有影響,但索引是有序的,所以更新索引時會產生資源爭用。如果你是RAC架構,由于GC多節點之間的相互爭用,會導致熱點塊問題進一步加劇。
傳統的解決方案是利用Oracle提供的逆鍵索引,把鍵值反過來,分散熱點塊。但逆鍵索引有一個很大的缺點,就是它雖然可以解決熱點問題,但卻不支持范圍掃描。
哈希分區如何解決呢?我們創建索引,指定索引按照哈希方式分區,然后指定分區數量。這樣做的好處是什么呢?原來我是一個索引,只有一個最高值,大家都去爭搶這一個最高值,但是現在我變成了32個分區,有32個索引最高值,這時的資源爭搶就會少很多。當然,技術都是有兩面性的,在這種情況下,你再做索引范圍掃描時,就不只是要掃一棵索引樹,而是32棵索引樹,引入的額外開銷就會大許多。所以分區數量的選擇也是十分有講究的。
列表分區最常見的是針對有某些業務屬性數據的場景。我們可以根據明確的業務特點去做分區。
地區字段是列表分區常見的候選鍵值列,數據分布和訪問方式確定分區鍵值劃分,同時我還建議設定一個DEFAULT分區,假設,我們把國內的大部分省到列出來了,但是有一天有個沒有對應分區的省的數據進來了,如果沒有DEFAULT分區就會直接報錯,而有了這個分區,數據就有容身之所了。
列表分區與業務的匹配度更好,業務可以清楚的知道數據存在哪里,并且高效的找到,不用太多的使用Oracle內部的關聯和查詢。
常見的索引有兩種,一種是全局索引,一種是本地索引。分區的全局索引和單表上的索引沒有區別,不管表上有多少個分區,只有一棵索引樹,所有的數據來自分區。這樣做的好處了,即使表做了分區,訪問代價也不會增加,但缺點是如果你對下面的分區表做了一些DDL操作,那么很容易導致索引失效。
本地索引和表分區是一一對應的關系,當你在對表做數據操作時,Oracle同時也會對索引分區做操作,不會導致分區索引的不可用,同時本地索引還支持并行掃描和創建。
本地索引的缺點是如果你要把主鍵創建成本地索引,那么主鍵必須包含在索引里面,而且無法保證每棵獨立的索引樹之間的數據一致性,所以必須把鍵值列加入其中來保證唯一性,但是這樣未限定分區的查詢將掃描全部索引分區,這會增加額外的開銷。
最后,我們看一下用來消除熱點塊的哈希分區索引,索引雖然也會做分區,但是與表數據沒有任何關聯關系,任何一個索引分區都可以去訪問所有的表,它的優勢就是分散熱點。但缺點是訪問索引時需要訪問索引的每個分區才能得到完整記錄。
四.分區最新特性
Oracle 12提供了很多新特性,這些新特性對于日常維護是非常有價值的,所以我們來為大家詳細介紹一下。
首先,我們來介紹部分分區。剛才我們講到常用的索引有兩種,全局索引和本地索引,那么部分分區的索引是什么呢?在實際環境中,我沒必要對所有分區都創建索引,很多歷史數據分區的訪問頻度是非常小的,沒有必要關注,部分分區索引剛好滿足這樣的應用場景,它可以把索引范圍壓縮到一個合理范圍內。
假設創建了一張分區表,里面有9個分區,分別存儲了17年和18年的數據,其中存儲17年數據的四個分區我們做了INDEX OFF操作,在創建索引時,我們會發現雖然創建了9個索引段,但做了操作的四個分區是不可用的,實際只創建了5個索引段。
當你訪問部分分區索引時,它會直接把執行計劃分成兩部分,一部分是在索引段里掃描,還有一部分是在對應內容里掃描。部分分區索引其實最大的改變是它可以分辨哪些索引是可用的,哪些是不可用的。
如果在指定鍵值的同時再加上一個時間,那這個時間就是我們分區線。當我們訪問數據時,Oracle就可以根據時間知道我要訪問哪個區,其它無需訪問的區雖然也是有數據的,但Oracle會在這里有個設置恒為假條件的filter,當訪問到這里時會直接跳到下一部分。
Oracle 12.1非常強大的一個功能點是索引異步維護。當創建范圍分區時,由于經常要做DDL的清理,所以不建議大家去建全局索引。但是Oracle 12解決了這個問題,假設1月4日對應數據分區里有31萬條記錄,3月5日對應的數據分區有近30萬條記錄,當我們去做創建分區操作時,花費時間大約為0.18秒,然后再檢查狀態時,不出意外,全局索引已經失效了。重建之后,我們在分區創建時加上一個Update Index的操作,因為要同步DDL操作,它會更新所有狀態,很多人認為它會變得非常慢,其實它只用了0.17秒,比之前的0.18秒還要快。這是因為Oracle 12之后,它會自動給數據打標識,并不是真正同步去維護,而是在后臺異步維護,不僅提高了索引的可用性,同時還提高了效率。
Oracle 12.2很有意思的一個特性是自動列表分區,我們之前建議在列表分區時一定要加上DEFAULT值,否則數據插入會報錯,尤其是當一張表只有一個Keyboard,在自動列表分區中插入數據是非常困難的。而Oracle提供的很方便的功能是在線把一張普通表轉換成分區表,這樣我就不會因為是分區表而引入停機、維護等。
Oracle 18c中針對這種情況提供了更強的改變,例如我創建了一個分區表和三個索引,當我從普通表變成分區表之后,但我對分區表策略不滿意,可以直接通過Oracle語句來改變數據表策略,而且這個操作可以在DDL發生時在線去做。
最后一個功能是針對變更之后的索引,我們可以在線去做分區的MERGE操作,通過在線的方式把其中幾個分區合并。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。