>進(jìn)入 前不久,曾經(jīng)接手一個(gè)性能調(diào)優(yōu)案例:這是一個(gè)報(bào)表系統(tǒng),其基礎(chǔ)數(shù)據(jù)主要存儲(chǔ)于三張表中。表的大小已經(jīng)很大了,最大一張接近100G。在生成報(bào)表時(shí)需要長(zhǎng)時(shí)間才能返回結(jié)果,一些online查詢甚至經(jīng)常ti" />
歡迎進(jìn)入Oracle社區(qū)論壇,與200萬(wàn)技術(shù)人員互動(dòng)交流 >>進(jìn)入 前不久,曾經(jīng)接手一個(gè)性能調(diào)優(yōu)案例:這是一個(gè)報(bào)表系統(tǒng),其基礎(chǔ)數(shù)據(jù)主要存儲(chǔ)于三張表中。表的大小已經(jīng)很大了,最大一張接近100G。在生成報(bào)表時(shí)需要長(zhǎng)時(shí)間才能返回結(jié)果,一些online查詢甚至經(jīng)常timeou
歡迎進(jìn)入Oracle社區(qū)論壇,與200萬(wàn)技術(shù)人員互動(dòng)交流 >>進(jìn)入
前不久,曾經(jīng)接手一個(gè)性能調(diào)優(yōu)案例:這是一個(gè)報(bào)表系統(tǒng),其基礎(chǔ)數(shù)據(jù)主要存儲(chǔ)于三張表中。表的大小已經(jīng)很大了,最大一張接近100G。在生成報(bào)表時(shí)需要長(zhǎng)時(shí)間才能返回結(jié)果,一些online查詢甚至經(jīng)常timeout。表中存儲(chǔ)的是2萬(wàn)多個(gè)公司的數(shù)據(jù),報(bào)表的生成也是以公司為單位的,因此,這一調(diào)優(yōu)方案的思路比較明確:將表按公司分區(qū)。但是,這中間卻存在一些麻煩:每個(gè)公司的數(shù)據(jù)并不是均衡的。其中近200家公司屬于VIP用戶,他們的數(shù)據(jù)量最大,每個(gè)公司差不多是十幾萬(wàn)到幾十萬(wàn)的數(shù)據(jù)量,其總量占了全部數(shù)據(jù)的30%左右;而其它非VIP用戶的數(shù)據(jù)基本上每個(gè)都在1萬(wàn)以內(nèi)。而我們的主要目標(biāo)就是要優(yōu)先保證VIP用戶獲取到最佳的性能(由于其數(shù)據(jù)量,當(dāng)前最大的性能問(wèn)題恰恰就出在這些VIP用戶上)。因此,我們提出了2中分區(qū)方案:
基于Company Id的Hash分區(qū);
基于Company Id的List分區(qū);
但是,這兩種方案各有優(yōu)缺點(diǎn):
對(duì)于Hash分區(qū),分區(qū)的大小更加均衡,因而性能也更加均衡。但是,可能出現(xiàn)一些無(wú)法控制的極端現(xiàn)象:Hash分區(qū)僅僅是對(duì)Company Id使用Hash函數(shù)進(jìn)行分組,它能做到每個(gè)分區(qū)分配基本相當(dāng)數(shù)量的Company Id,但是每個(gè)Company Id對(duì)應(yīng)的數(shù)據(jù)量并不考慮在內(nèi),因此可能出現(xiàn)某些分區(qū)集中的都是VIP數(shù)據(jù)或者都是非VIP數(shù)據(jù),造成分區(qū)過(guò)大或過(guò)小;另外一個(gè)缺點(diǎn)就是我們很難直接干預(yù)某個(gè)公司的性能。例如,可能有某個(gè)非VIP用戶成為了VIP用戶,其數(shù)據(jù)量激增,它又正好處于一個(gè)大的分區(qū)上,這時(shí),我們很難將其從這個(gè)分區(qū)剝離出來(lái),除非它所在分區(qū)正好出在一個(gè)即將分裂的分區(qū)上。
對(duì)于List分區(qū),VIP用戶的性能能夠得到保證。我們可以將每個(gè)VIP用戶單獨(dú)存儲(chǔ)在一個(gè)分區(qū)上,但是,不可能將非VIP用戶單獨(dú)存儲(chǔ)開(kāi)(不僅增加維護(hù)難度,且增加整個(gè)表的大小),只能將非VIP用戶存儲(chǔ)在幾個(gè)分區(qū)上。但是這樣還是造成DDL語(yǔ)句非常復(fù)雜,并且非VIP的分區(qū)很大(每個(gè)都在10G左右,而VIP分區(qū)最大才200M)。
由于List分區(qū)更加接近我們的優(yōu)化目的,最終還是采用了List分區(qū)。
其實(shí),期間我們?cè)?jīng)考慮過(guò)使用復(fù)合分區(qū)。在10g中(我們的生產(chǎn)庫(kù)是10g),僅支持2種復(fù)合分區(qū):Range-List和Range-Hash。我們的解決方案是:為表增加一個(gè)數(shù)字類型的ID字段,VIP用戶對(duì)應(yīng)的數(shù)字大于100,000,非VIP用戶的ID小于100,000。每個(gè)VIP用戶被單獨(dú)放置在一個(gè)Range分區(qū)中,所有非VIP用戶被放置在一個(gè)Range分區(qū)中,然后再對(duì)非VIP分區(qū)通過(guò)Hash劃分子分區(qū)。這樣,即能保證VIP用戶的性能,也能均衡非VIP用戶的性能。但是,由于這種方案需要增加一個(gè)非業(yè)務(wù)的字段,以及其它一些原因,最終被否決了。
到11g中,Oracle的分區(qū)策略更加靈活了。首先,11g支持更多方式的組合分區(qū),除10g支持的兩種之外,還支持Range-Range、List-Range、List-List、List-Hash的組合分區(qū)策略。對(duì)于我們上述這個(gè)案例,就可以通過(guò)List-Hash的組合分區(qū)來(lái)解決。以下就是一個(gè)List-Hash分區(qū)的演示:
SQL代碼
SQL> create table par_test
2 partition by list (owner)
3 subpartition by hash (owner)
4 store in (example)
5 (partition p1 values ('SYS'), 6 partition p2 values ('PUBLIC'),
7 partition def values (default)
8 subpartitions 4
9 )
10 as select * from dba_objects
11 /
Table created.
SQL> analyze table par_test compute statistics;
Table analyzed. SQL> select partition_name, subpartition_name, num_rows, blocks from dba_tab_subpartitions
2 where table_name = 'PAR_TEST';
PARTITION_NAME SUBPARTITION_NAME NUM_ROWS BLOCKS
------------------------------ ------------------------------ ---------- ----------
P2 SYS_SUBP154 26604 434
DEF SYS_SUBP158 4529 70
DEF SYS_SUBP157 2783 45
DEF SYS_SUBP156 2422 39
DEF SYS_SUBP155 2854 47
P1 SYS_SUBP153 29770 437
6 rows selected.
順便再提一下11g新增的其他分區(qū)策略。
針對(duì)Range Partition,11g有了一種更加靈活的方式:Interval Partition。例如,我們一些分區(qū)表是依賴于時(shí)間做的范圍分區(qū):每個(gè)月的數(shù)據(jù)存放到一個(gè)分區(qū)中。隨著數(shù)據(jù)的增長(zhǎng),還需要有一個(gè)作業(yè)來(lái)增加新的分區(qū)以滿足上述策略。而在11g中,通過(guò)Interval Parition,就無(wú)需這中人為的維護(hù)作業(yè)了,Oracle會(huì)為新的數(shù)據(jù)自動(dòng)增加分區(qū):
SQL代碼
SQL> create table par_test2 (a number, b date)
2 partition by range (b)
3 interval (numtoyminterval(1,'MONTH'))
4 store in (example)
5 (
6 partition values less than (to_date('2009-09-01','yyyy-mm-dd'))
7 )
8 ;
Table created. SQL> insert into par_test2 values(1, sysdate); 1 row created.
SQL> commit;
Commit complete. SQL> select partition_name, high_value from dba_tab_partitions
2 where table_name = 'PAR_TEST2';
PARTITION_NAME HIGH_VALUE
------------------------------ --------------------------------------------------------------------------------
SYS_P164 TO_DATE(' 2009-09-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIA ' SQL> insert into par_test2 values(1, to_date('2009-10-01','yyyy-mm-dd')); 1 row created.
SQL> commit;
Commit complete. SQL> select partition_name, high_value from dba_tab_partitions
2 where table_name = 'PAR_TEST2';
PARTITION_NAME HIGH_VALUE
[1] [2]
聲明:本網(wǎng)頁(yè)內(nèi)容旨在傳播知識(shí),若有侵權(quán)等問(wèn)題請(qǐng)及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com