Oracle分區實戰


前言

  由於近期做的一個項目每個月需要插入大約一百萬條數據,這樣的話,一年的數據就是一千萬以上的數據,而且項目的業務要求的查詢條件都是模糊查詢,所以索引不起作用,最后決定對表進行分表分區,由於分表需要分析項目的業務作出最適合的分表方式,分表只要選定了以什么來分,就不難了。這篇文章講述的是對表的分區,由於數據是按月插入的,所以我按照的是按月分區(即Oracle按時間分區)。

分區的目的

  數據庫分區:就是減少SQL操作的數據量,從而提升查詢效率。表分區后,邏輯上仍然是一張表,只不過將表中的數據在物理上存放到多個表空間上。這樣在查詢數據時,會查詢相應分區的數據,避免了全表掃描。

  分區又分為水平分區、垂直分區。

  水平分區:就是對行進行分區,舉個例子來說,就是一個表中有1000萬條數據,每100萬條數據划一個分區,這樣就將表中數據分到10個分區中去。水平分區要通過某個特定的屬性列進行分區,比如我用的列就是Date時間。

  垂直分區:通過對標垂直划分來減少表的寬度,從而提升查詢效率。比如一個學生表中,有他相關的信息列,還有論文列以CLOB存儲。這些以CLOB存儲的論文並不會經常被訪問到,這時候就要把這些不經常使用的CLOB划分到另一個分區,需要訪問時再調用它。

  總的來說,分區的主要目的還是避免了全表掃描,從而提升查詢速度。

實戰開始

  先來看一下我的建表語句。

 1 -- Create table
 2 create table BUS_DAILY_BALANCE_01
 3 (
 4   opt_id          NUMBER(18) not null,
 5   nowdate         date,
 6   openbank_no     VARCHAR2(40),
 7   openbank_name   VARCHAR2(40),
 8   customer_name   VARCHAR2(40),
 9   customer_no     VARCHAR2(40),
10   account_name    VARCHAR2(40),
11   account_no      VARCHAR2(40),
12   subaccount_no   VARCHAR2(40),
13   account_type    VARCHAR2(80),
14   account_quality VARCHAR2(80),
15   sign_virtual    VARCHAR2(40),
16   sign_collect    VARCHAR2(40),
17   daily_average   NUMBER(18,2),
18   balance         NUMBER(18,2)
19 )
20 tablespace TS_PJAVA_DATA
21 PARTITION BY RANGE (nowdate)
22 (
23   partition BUS_DAILY_P1800 values less than (to_date('2018-01-01','yyyy-mm-dd')),
24   partition BUS_DAILY_P1801 values less than (to_date('2018-02-01','yyyy-mm-dd')),
25   partition BUS_DAILY_P1802 values less than (to_date('2018-03-01','yyyy-mm-dd')),
26   partition BUS_DAILY_P1803 values less than (to_date('2018-04-01','yyyy-mm-dd')),
27   partition BUS_DAILY_P1804 values less than (to_date('2018-05-01','yyyy-mm-dd')),
28   partition BUS_DAILY_P1805 values less than (to_date('2018-06-01','yyyy-mm-dd')),
29   partition BUS_DAILY_P1806 values less than (to_date('2018-07-01','yyyy-mm-dd')),
30   partition BUS_DAILY_P1807 values less than (to_date('2018-08-01','yyyy-mm-dd')),
31   partition BUS_DAILY_P1808 values less than (to_date('2018-09-01','yyyy-mm-dd')),
32   partition BUS_DAILY_P1809 values less than (to_date('2018-10-01','yyyy-mm-dd')),
33   partition BUS_DAILY_P1810 values less than (to_date('2018-11-01','yyyy-mm-dd')),
34   partition BUS_DAILY_P1811 values less than (to_date('2018-12-01','yyyy-mm-dd')),
35   partition BUS_DAILY_P1812 values less than (to_date('2019-01-01','yyyy-mm-dd')),
36   partition BUS_DAILY_P1901 values less than (to_date('2019-02-01','yyyy-mm-dd')),
37   partition BUS_DAILY_P1902 values less than (to_date('2019-03-01','yyyy-mm-dd')),
38   partition BUS_DAILY_P1903 values less than (to_date('2019-04-01','yyyy-mm-dd')),
39   partition BUS_DAILY_P1904 values less than (to_date('2019-05-01','yyyy-mm-dd')),
40   partition BUS_DAILY_P1905 values less than (to_date('2019-06-01','yyyy-mm-dd')),
41   partition BUS_DAILY_P1906 values less than (to_date('2019-07-01','yyyy-mm-dd')),
42   partition BUS_DAILY_P1907 values less than (to_date('2019-08-01','yyyy-mm-dd')),
43   partition BUS_DAILY_P1908 values less than (to_date('2019-09-01','yyyy-mm-dd')),
44   partition BUS_DAILY_P1909 values less than (to_date('2019-10-01','yyyy-mm-dd')),
45   partition BUS_DAILY_P1910 values less than (to_date('2019-11-01','yyyy-mm-dd')),
46   partition BUS_DAILY_P1911 values less than (to_date('2019-12-01','yyyy-mm-dd')),
47   partition BUS_DAILY_P1912 values less than (to_date('2020-01-01','yyyy-mm-dd')),
48   partition BUS_DAILY_P2001 values less than (to_date('2020-02-01','yyyy-mm-dd')),
49   partition BUS_DAILY_P2002 values less than (to_date('2020-03-01','yyyy-mm-dd')),
50   partition BUS_DAILY_P2003 values less than (to_date('2020-04-01','yyyy-mm-dd')),
51   partition BUS_DAILY_P2004 values less than (to_date('2020-05-01','yyyy-mm-dd')),
52   partition BUS_DAILY_P2005 values less than (to_date('2020-06-01','yyyy-mm-dd')),
53   partition BUS_DAILY_P2006 values less than (to_date('2020-07-01','yyyy-mm-dd')),
54   partition BUS_DAILY_P2007 values less than (to_date('2020-08-01','yyyy-mm-dd')),
55   partition BUS_DAILY_P2008 values less than (to_date('2020-09-01','yyyy-mm-dd')),
56   partition BUS_DAILY_P2009 values less than (to_date('2020-10-01','yyyy-mm-dd')),
57   partition BUS_DAILY_P2010 values less than (to_date('2020-11-01','yyyy-mm-dd')),
58   partition BUS_DAILY_P2011 values less than (to_date('2020-12-01','yyyy-mm-dd')),
59   partition BUS_DAILY_P2012 values less than (to_date('2021-01-01','yyyy-mm-dd')),
60   partition BUS_DAILY_PMAX values less than (maxvalue)
61   tablespace TS_PJAVA_DATA
62 );
63 -- Add comments to the columns 
64 comment on column BUS_DAILY_BALANCE.opt_id
65   is 'ID';
66 comment on column BUS_DAILY_BALANCE.nowdate
67   is '日期';
68 comment on column BUS_DAILY_BALANCE.openbank_no
69   is '開戶機構名稱';
70 comment on column BUS_DAILY_BALANCE.openbank_name
71   is '開戶機構';
72 comment on column BUS_DAILY_BALANCE.customer_name
73   is '客戶名稱';
74 comment on column BUS_DAILY_BALANCE.customer_no
75   is '客戶編號';
76 comment on column BUS_DAILY_BALANCE.account_name
77   is '賬戶名稱';
78 comment on column BUS_DAILY_BALANCE.account_no
79   is '賬戶號';
80 comment on column BUS_DAILY_BALANCE.subaccount_no
81   is '子賬戶號';
82 comment on column BUS_DAILY_BALANCE.account_type
83   is '賬戶類型';
84 comment on column BUS_DAILY_BALANCE.account_quality
85   is '賬戶性質';
86 comment on column BUS_DAILY_BALANCE.sign_virtual
87   is '是否簽約虛擬賬簿';
88 comment on column BUS_DAILY_BALANCE.sign_collect
89   is '是否簽約資金歸集';
90 comment on column BUS_DAILY_BALANCE.daily_average
91   is '日均余額';
92 comment on column BUS_DAILY_BALANCE.balance
93   is '余額';

 上面的建表分區語句,沒有采用Oracle自動分區,自動分區的分區表名不受控制,是以“SYS_P”開頭,當然網上有通過存儲過程來修改,可百度查詢。

分區表的維護

(1)添加分區

ALTER TABLE tablename ADD PARTITION partition_name VALUES LESS THAN(TO_DATE('2003-06-01','YYYY-MM-DD'));

   注意:以上添加的分區界限應該高於最后一個分區界限。

(2)刪除分區

ALTER TABLE tablename DROP PARTITION partition_name;

  注意:如果刪除的分區是表中唯一的分區,那么此分區將不能被刪除,要想刪除此分區,必須刪除表。

(3)截斷分區

  截斷某個分區是指刪除某個分區中的數據,並不會刪除分區,也不會刪除其它分區中的數據。當表中即使只有一個分區時,也可以截斷該分區。通過以下代碼截斷分區:

ALTER TABLE tablename TRUNCATE PARTITION partition_name;

(4)合並分區

  合並分區是將相鄰的分區合並成一個分區,結果分區將采用較高分區的界限,值得注意的是,不能將分區合並到界限較低的分區。

ALTER TABLE tablename MERGE PARTITIONS partition_name1,partition_name2 INTO PARTITION partition_name2 UPDATE INDEXES;

  如果省略update indexes子句的話,必須重建受影響的分區的index;

ALTER TABLE tablename MODIFY PARTITION partition_name REBUILD UNUSABLE LOCAL INDEXES;

(5)拆分分區

  拆分分區將一個分區拆分兩個新分區,拆分后原來分區不再存在。注意不能對HASH類型的分區進行拆分。

ALTER TABLE tablename SPLIT PARTITION partition_name AT(TO_DATE('2003-02-01','YYYY-MM-DD')) INTO (PARTITION partition_name1,PARTITION partition_name2);

(6)接合分區(coalesce

  分區接合是針對散列分區或者*-散列子分區的,目的是減少分區數。當某個散列分區接合后,Oracle將其分區的數據分散到其它分區中。被接合的分區是由數據庫選擇的,接合完成后該分區會被刪除,且如果沒有使用UPDATE INDEX子句,本地索引和全局索引均將變成不可用,一般需要重建索引。

--散列分區表的散列分區接合
ALTER TABLE table_name COALESCE PARTITION;

(7)重命名分區

ALTER TABLE table_name RENAME PARTITION old_name TO new_name;

(8)移動分區

alter table tablename move partition partition_name tablespace newtablespace;

  分區移動會自動維護局部分區索引,oracle不會自動維護全局索引,所以需要我們重新rebuild分區索引,具體需要rebuild哪些索引,可以通過dba_part_indexes,dba_ind_partitions去判斷。

Select index_name,status From user_indexes Where table_name='tablename';

分區表的查詢

(1)跨分區查詢

select sum( *) from
(select count(*) cn from t_table_SS PARTITION (partition_name1)
union all
select count(*) cn from t_table_SS PARTITION (partition_name2)
);

(2)查詢表上有多少個分區

SELECT * FROM USER_TAB_PARTITIONS WHERE TABLE_NAME='tableName';

(3)其他的一些查詢

--顯示數據庫所有分區表的信息:
select * from DBA_PART_TABLES
 
--顯示當前用戶可訪問的所有分區表信息:
select * from ALL_PART_TABLES
 
--顯示當前用戶所有分區表的信息:
select * from USER_PART_TABLES
 
--顯示表分區信息 顯示數據庫所有分區表的詳細分區信息:
select * from DBA_TAB_PARTITIONS
 
--顯示當前用戶可訪問的所有分區表的詳細分區信息:
select * from ALL_TAB_PARTITIONS
 
--顯示當前用戶所有分區表的詳細分區信息:
select * from USER_TAB_PARTITIONS
 
--顯示子分區信息 顯示數據庫所有組合分區表的子分區信息:
select * from DBA_TAB_SUBPARTITIONS
 
--顯示當前用戶可訪問的所有組合分區表的子分區信息:
select * from ALL_TAB_SUBPARTITIONS
 
--顯示當前用戶所有組合分區表的子分區信息:
select * from USER_TAB_SUBPARTITIONS
 
--顯示分區列 顯示數據庫所有分區表的分區列信息:
select * from DBA_PART_KEY_COLUMNS
 
--顯示當前用戶可訪問的所有分區表的分區列信息:
select * from ALL_PART_KEY_COLUMNS
 
--顯示當前用戶所有分區表的分區列信息:
select * from USER_PART_KEY_COLUMNS
 
--顯示子分區列 顯示數據庫所有分區表的子分區列信息:
select * from DBA_SUBPART_KEY_COLUMNS
 
--顯示當前用戶可訪問的所有分區表的子分區列信息:
select * from ALL_SUBPART_KEY_COLUMNS
 
--顯示當前用戶所有分區表的子分區列信息:
select * from USER_SUBPART_KEY_COLUMNS
 
--怎樣查詢出oracle數據庫中所有的的分區表
select * from user_tables a where a.partitioned='YES'
 
--刪除一個表的數據是
truncate table table_name;
 
--刪除分區表一個分區的數據是
alter table table_name truncate partition partition_name; 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM