10.3.1 分區(qū)和插入性能
考慮插入的性能。Sybase最早對于分區(qū)的努力將能追溯至版本11.0,它旨在幫助查詢性能。盡管如此,真正的驅(qū)動原因是降低或消除堆表最后一頁的競爭。那時,Sybase僅支持全頁鎖定(APL),因此,并發(fā)的表插入常常被序列化到表的最后一頁上。但是,它充其量只是些許的幫助,因為對于不斷增加的數(shù)據(jù)元素,索引競爭依然存在(例如順序列或當(dāng)前時間)。隨著11.9版本中數(shù)據(jù)行鎖定的發(fā)布,通過分區(qū)來解除競爭的需求不再。但是,11.x/12.x中的輪循分區(qū)模式對插入性能幫助很大,因為它使用用戶的SPID來決定用戶數(shù)據(jù)將插入哪個分片中。不幸的是,在ASE 12.5及之前的版本,沒有辦法分別將特定的分區(qū)分片放置于與其他分片不同的指定段上—因此,沒有達(dá)到完整的IO并發(fā)效果。ASE 15.0改進了輪循分區(qū),支持不同分區(qū)放置于不同段,映射至不同設(shè)備上,從而支持IO并發(fā)。
使用分區(qū)需要考慮的一個方面就是使用全局索引或本地索引。全局索引—缺省項—通過單獨的b-樹結(jié)構(gòu)實現(xiàn)如圖23。
圖23 分區(qū)表上的全局索引
圖24 分區(qū)表上的本地(分區(qū))索引
正如所展示的,索引作為一個整體未分區(qū)的結(jié)構(gòu)存儲。另一方面,本地(分區(qū))索引使用了與附表相同的分區(qū)模式和分區(qū)鍵進行分區(qū)。本地索引的結(jié)果類似,如圖24。
注意索引本身是分區(qū)的。每種方法各有優(yōu)劣,如表18。
表18 全局、本地(分區(qū))索引優(yōu)劣
在本地索引中(2),(3)部分的優(yōu)勢需要進一步解釋為何其優(yōu)勢不如期望的那么大。根據(jù)每個分區(qū)的行數(shù)和索引鍵大小,本地分區(qū)可能中間級別的節(jié)點較少—即“較小”的索引高度。正如上面所顯示的,原先的索引高度為4,而分區(qū)索引二的高度為三,分區(qū)三的高度為2。
10.3.2 分區(qū)與插入性能
這將能稍微改善每個插入的性能,因為需要更少的IO索引樹遍歷來插入每個索引鍵值。例如,假設(shè)在上表上有5個索引。在未分區(qū)的表中,將遍歷主鍵/聚集索引以尋找行的插入點(讀取索引樹需要4個IO,1個用于讀取數(shù)據(jù)頁,加上寫入數(shù)據(jù)頁和寫入索引頁節(jié)點)。所以不得不遍歷其他4個索引來尋找索引插入點(4個IO用于讀取每個索引樹加上對每個葉頁面的寫入)。假設(shè)不會發(fā)生頁面分列、溢出頁面等,一個對表的插入成本(只考慮讀?。┤绫?9。
表19 插入成本讀取
作為對比,可考慮在范圍分區(qū)的最末端分區(qū)上的插入。最常見的范圍分區(qū)實現(xiàn)是“翻滾分區(qū)”,最后一個分區(qū)就是當(dāng)前的插入點。結(jié)果,最初的分區(qū)插入可能只會有一個索引級別。假設(shè)如上面展示的,它達(dá)到了最大值2,則讀取的IO成本應(yīng)如表20。
表20 IO成本讀取
也不是太驚人—一半。該問題可以很快地被引申至查詢的執(zhí)行也只需要一半的時間。這并非必須。從一個獨立用戶的角度,這可能不明顯。例如,很可能索引樹的最近部分都在數(shù)據(jù)緩存中—因此,所有的讀取都是邏輯讀取??紤]到邏輯讀取的速度(內(nèi)存訪問),節(jié)省的時間可能只是幾毫秒??刹捎靡韵聹y試來證明:
(1)創(chuàng)建了一張有5個索引的數(shù)據(jù)行鎖定表(未分區(qū))。該表預(yù)裝了約3千萬行數(shù)據(jù)。然后在單獨的主機上有20個客戶端線程使用延遲提交和完整的準(zhǔn)備語句執(zhí)行1百萬個原子插入。客戶端線程也可放在相同的主機上—或者就簡單地在ASE中進行處理,目的只是要模仿更為真實的配置。
(2)該表被刪除,隨后重建,使用基于date列上的30個分區(qū)。該表仍有5個索引—但是其中之一被創(chuàng)建為全局索引。最初的3千萬行數(shù)據(jù)被插入前面的29個分區(qū)中。相同的20個客戶端線程將1百萬行數(shù)據(jù)插入最后(第30個)分區(qū)中。
(3)使用基于date列的30個哈希分區(qū)重復(fù)第二項測試。結(jié)果將使30個分區(qū)中值分布均衡。
(4)使用輪循分區(qū)(30個分區(qū))重復(fù)測試。由于輪循分區(qū)不支持本地索引,5個索引都被創(chuàng)建為全局索引。
(5)用30個范圍分區(qū)重復(fù)同樣的測試—單本次都使用本地索引。
(6)同樣的測試在全部本地索引的哈希分區(qū)上重復(fù)。
結(jié)果如表21。
表21 表分區(qū)索引數(shù)據(jù)
正如可以看到的,將全局索引改變?yōu)楸镜厮饕龑⒅荒芄?jié)省在大約160 s中5 s~6 s—或大約4%的時間。其次,范圍和輪循分區(qū)也只僅僅比基表插入快一點—除非范圍分區(qū)表僅包含本地索引。另一方面,哈希分區(qū)落后于未分區(qū)表,除非將全局索引改變?yōu)楸镜厮饕?。哈希值?0個分區(qū)中的分布被驗證有2%的中間數(shù)值,因此并非是非平衡的模式造成的。值得注意的是,如果僅有20個客戶端,輪循模式僅使用30個分區(qū)中的20個—因此它是非平衡的。這對輪循分區(qū)是正常的。以上部分的結(jié)論是什么呢?
(1)如果因插入性能而分區(qū),在全頁鎖定下將得到最佳效果,因為嚴(yán)格分區(qū)是降低競爭的手段。另一替代方法是僅使用數(shù)據(jù)行鎖定。比數(shù)據(jù)行鎖定還好的的是基于哈希的分區(qū)(以降低競爭),因為本地索引將能在索引級別幫助緩解競爭(與輪循分區(qū)比較)。
(2)單獨插入在分區(qū)上提升最小,因為索引的高度將由在緩存中的邏輯IO彌補,因為它們已經(jīng)夠快了而額外的索引級別并不會太顯眼。
(3)可能能在真正小且持續(xù)小分區(qū)上獲得提升,因為與未分區(qū)表相比,索引高度可能有幾個或更多級別的巨大差別。
實際上,均衡分區(qū)對插入的優(yōu)勢可忽略不計,而對至少兩個有序較小分區(qū)的插入可能優(yōu)勢更大。
10.3.3 分區(qū)和查詢性能
如果分區(qū)對插入性能沒有太大幫助的話—那么減少的索引高度何時才能起作用呢?答案是在包含了連接的查詢中…當(dāng)然也有可能有傷害。先來看看它的優(yōu)勢。在上例中,對表新增了一百萬行。我們假設(shè)在夜里會運行一些批處理任務(wù),用于鑒別需要進一步處理的特殊記錄。典型的批處理任務(wù)看起來像:
select row _id=identity(20),
into #rowsToBeProcessed
from trans _detail
where
and tran_date between
update trans_detail
set
from #rowsToBeProcessed r, trans_detail t
where r.
普通得就像電燈開關(guān)一樣。不同之處是通常只影響一小部分子集的更新被嵌入循環(huán)中以避免競爭。
繼續(xù)假設(shè)該批處理將在最近的行中鑒別出10%的行—本例中是10萬行。基于3 100萬行的不同分區(qū)模式的統(tǒng)計結(jié)果見表22。
表22 分區(qū)模式統(tǒng)計結(jié)果
在本例中,再次顯示出只節(jié)省了10萬次邏輯IO– 它意味著更少的物理IO因為不太可能所有需要的行都在內(nèi)存中—它能從根本上減少執(zhí)行時間。注意,即使是全部緩存的情況下,10萬個邏輯IO也不足以彌補額外的查詢編譯和開銷復(fù)雜度—但是也僅討論了3 000萬行數(shù)據(jù)。包含了1億條數(shù)據(jù)的分區(qū)表可能會有優(yōu)勢。和原來一樣,可能區(qū)別很大。
區(qū)別一方面可能依賴于查詢的類型。例如,考慮以下典型的范圍查詢:
-- list all the transactions for a customer in last 10 days
-- (local) index on customer_id, tran_date
select *
from trans_detail
where customer_id =
and tran_date between dateadd (dd,-10, getdate ()) and getdate ()
現(xiàn)在,假設(shè)DBA成功說服了用每天一個分區(qū)的范圍分區(qū)來簡化維護需求。在該情況下,查詢比未分區(qū)表需要更長時間,使用更多IO!
未分區(qū)表—查詢將遍歷索引尋找第一行(10天前的)然后執(zhí)行表或索引范圍掃描直至當(dāng)前行。
范圍分區(qū)表(每天一個分區(qū))—查詢將遍歷10個分區(qū)中的每個本地索引,然后在每個分區(qū)中執(zhí)行表/索引范圍掃描來找到前10天的數(shù)據(jù)。
假設(shè)在高度為8的索引上每天100個事務(wù),且5個事務(wù)一頁,則未分區(qū)表將使用總計8(索引) + 200(掃描)=208個邏輯IO。范圍分區(qū)表將需要8*10=80(索引遍歷) + 10*20 = 200 (掃描),總IO成本為280。雖然區(qū)別頗小,但請考慮如果查詢跨越一年的問題—它將會有365個分區(qū)。不僅如此—并非所有的數(shù)據(jù)都在內(nèi)存中—使用未分區(qū)表,服務(wù)器將選擇異步預(yù)取(APF)和大IO來從磁盤中快速讀取數(shù)據(jù),而在較小的分區(qū)中可能需要對每個掃描選擇開啟APF和大IO。這將造成總體成本偏高—可能到達(dá)優(yōu)化器選擇另一低成本索引的程度(或甚至是分區(qū)掃描),如果統(tǒng)計值陳舊。
關(guān)鍵要考慮的因素是要確保分區(qū)范圍與業(yè)務(wù)需求一致。例如,大部分商業(yè)操作是基于季度的—因此按照完整的季度范圍的日期分區(qū)將能滿足大部分查詢(諸如典型的季度銷售、季度的語句和季度與季度間的分析)能完全利用APF和大IO。而DBA可能感到維護影響,考慮以下內(nèi)容:
(1)大部分大型維護操作都被安排在周末—通??赡芤粋€季度只有一次。因此,像歸檔這樣的大型操作可能每個季度只發(fā)生一次—粒度更小的分區(qū)沒有幫助。
(2)在某天發(fā)生的銷售將可能在后續(xù)幾天有諸如遞送、計費等銷售后的活動影響事務(wù)。因此,統(tǒng)計更新(可能)需要在分區(qū)上每周執(zhí)行一次。
(3)在一些業(yè)務(wù)中,大部分銷售都是季度的最后幾個星期中完成的—因此許多分區(qū)可能會是空的—或接近于空。
再次強調(diào),需求可能是不同的—但重要的是更了解業(yè)務(wù)需求的開發(fā)人員,而不是DBA,需要與DBA一起確保分區(qū)的粒度能滿足大部分的查詢范圍。顯然是不利的方面。
但是,也有一個有利的方面。還記得前面作為分區(qū)實現(xiàn),跨越多張物理表(用于積極聚合)的聯(lián)合視圖?語義分區(qū)對其有很大的優(yōu)勢。在原來的討論中,我們注意到在allrows_mix情況下,優(yōu)化器選擇使用將所有數(shù)據(jù)聯(lián)合至工作表中,對工作表排序然后再對銷售數(shù)據(jù)使用和并連接。使用工作表來做聯(lián)合是因為優(yōu)化器不清楚哪些數(shù)據(jù)在哪些“分區(qū)”(或表)中。例如,除了應(yīng)用程序邏輯外—沒有別的辦法能阻止2008數(shù)據(jù)出現(xiàn)在2007“分區(qū)”中。使用語義分區(qū),優(yōu)化器了解哪些數(shù)據(jù)在哪些分區(qū)中并能避免不必要的union all/合并排序。它列出了每種方法的優(yōu)劣,如表23。
表23 語義分區(qū)各種方法的優(yōu)劣
需要記住的是—不是二者必須選一—通過在一個或多個可能使用了語義分區(qū)的物理表上使用聯(lián)合視圖“分區(qū)表”,兩者可以結(jié)合使用。
ASE 15.0.x為應(yīng)用程序開發(fā)人員提供了一些有趣的功能以及必須從較早版本升級的理由。從新的較大數(shù)據(jù)類型—到可讀性較強的#temp表名—到函數(shù)索引和計算列—SQL用戶定義函數(shù)和替代觸發(fā)器—到查詢優(yōu)化的改善—對開發(fā)人員友好的新工具的功能—到XTP一覽—到表分區(qū)。
正如展示的,通常當(dāng)這些功能結(jié)合使用時,他們的威力才能被真正認(rèn)識。不論是為“自動解析”關(guān)鍵元素而在XML上建立的函數(shù)索引和計算列—還是在聯(lián)合視圖上的替代觸發(fā)器和DSS優(yōu)化,諸如跨OLTP和歸檔系統(tǒng)的積極聚合。結(jié)果證明了Sybase ASE的新發(fā)布不僅是對DBA需求的另一個升級平臺—而且為開發(fā)人員提供了滿足當(dāng)今對高容量/高速度業(yè)務(wù)環(huán)境中涌現(xiàn)出的應(yīng)用程序開發(fā)需求。