效率和速度 --表分割槽,物化檢視,索引
阿新 • • 發佈:2019-01-31
8.1 表分割槽
分而治之
目的:
- 安全(雞蛋不要放在一個籃子裡)
- 效率****(快速找到南方it學院所有姓張的人)
- 便於維護
場景:
- 資料量極大(大於 2G)
- 歷史資料比重比較大
分類:
- 範圍分割槽
- 列表分割槽
- 雜湊分割槽(hash)
在以上分割槽的基礎上,可以兩兩結合,形成 複合分割槽,但常用的就是兩種:
- 範圍-列表分割槽
- 範圍-雜湊分割槽
範圍分割槽:
-- 建立一個普通表的語句
create table person1 (id int primary key, name varchar2(20), birth date);
-- 資料將會在同一個表空間同一個段內
insert into person1 values (1, 'sss', sysdate);
-- 建立一個分割槽表
-- 這裡是按照生日進行範圍分割槽
-- 語句的基本格式就是在普通建表的語句上,增加 partition by 語句塊
create table person2 (name varchar2(20), birth date)
partition by range (birth)
(
partition p1 values less than (to_date('19950101','yyyymmdd')), -- 'values less than'
partition p2 values less than (to_date( '20000101','yyyymmdd')),
partition p3 values less than (maxvalue) -- 預設分割槽
);
-- 插入,資料會根據分割槽的情況進入不同的分割槽內
insert into person2 values ('張三', to_date('19940707'));
insert into person2 values ('李四', to_date('19980707'));
insert into person2 values ('王五', to_date('20040707'));
-- 查詢表中所有資料
select * from person2;
-- 查詢特定分割槽上資料
select * from person2 partition (p3);
-- 可以為不同的分割槽指定不同的表空間
-- 沒有指定表空間的分割槽,使用使用者的預設表空間
-- 所以,一個表內的資料可以存在於不同表空間裡,也就是可以存放在不同資料檔案中,不同磁碟上
-- 因此,分割槽表能增強資料的安全性
create table person3 (name varchar2(20), birth date)
partition by range (birth)
(
partition p1 values less than (to_date('19950101','yyyymmdd')) tablespace system,
partition p2 values less than (to_date('20000101','yyyymmdd')) tablespace sysaux,
partition p3 values less than (maxvalue) tablespace users
);
-- 可以在其他型別上進行範圍分割槽
-- 也可以在多個欄位上進行範圍分割槽
create table person4 (name varchar2(20), birth date, score number)
partition by range (birth, score)
(
partition p1 values less than (to_date('19900101','yyyymmdd'), 60),
partition p2 values less than (to_date('19900101','yyyymmdd'), 90),
partition p3 values less than (to_date('19990101','yyyymmdd'), 60),
partition p4 values less than (to_date('19990101','yyyymmdd'), 90),
partition p5 values less than (maxvalue, maxvalue)
);
列表分割槽:
-- 如果是生日的這樣的欄位,資料是連續的,應該使用範圍分割槽
create table person (name varchar2(20), birth date)
partition by range(birth)
(
partition p1 values less than (to_date('19900101', 'yyyymmdd')) tablespace users,
partition p2 values less than (maxvalue)
);
insert into person values ('aaa', to_date('19871212', 'yyyymmdd'));
select * from person partition (p1);
/*
where birth between 1987 and 1990
where sex in ('男', '女')
*/
-- 但是像性別、民族等欄位,更適合使用的是列表分割槽
-- 下面一個例子,使用性別作為分割槽欄位,男的一個區,女的一個區
create table person2 (name varchar2(20), sex varchar(10))
partition by list (sex)
(
partition p1 values ('男'),
partition p2 values ('女')
);
insert into person2 values ('aaa', '男');
insert into person2 values ('bbb', '女');
insert into person2 values ('ccc', '未知'); -- 報錯
select * from person2 partition (p2);
-- 預設分割槽的寫法
create table person3 (name varchar2(20), sex varchar(10))
partition by list (sex)
(
partition p1 values ('男'),
partition p2 values ('女'),
partition p3 values (default)
);
insert into person3 values ('ccc', '未知');
select * from person3 partition (p3);
-- 可以為每個分割槽指定表空間
create table person3 (name varchar2(20), sex varchar(10))
partition by list (sex)
(
partition p1 values ('男') tablespace users,
partition p2 values ('女') tablespace system,
partition p3 values (default)
);
雜湊分割槽:
-- 雜湊分割槽
-- 主要用在一些比較離散,不好分類的資料上,比如產品名字
-- 讓 oracle 使用雜湊演算法自動計算資料的分割槽
-- 建立語句,非常簡單
create table person4 (name varchar2(20), sex varchar2(10))
partition by hash (name)
(
partition p1,
partition p2 tablespace users
);
insert into person4 values ('aaa', '男');
insert into person4 values ('收款', '男');
select * from person4 partition (p1);
-- 上面的語句可以進一步簡化為:
create table person5 (name varchar2(20), sex varchar2(10))
partition by hash (name)
partitions 5;
-- 為每個分割槽指定表空間
create table person6 (name varchar2(20), sex varchar2(10))
partition by hash (name)
partitions 3 store in (users, system, sysaux);
範圍-列表分割槽:
-- 首先,按照生日進行列表分割槽,分了三個區
-- 其次,在每個分割槽內,又按照性別分了三個區
-- 所以,總共是 3 個分割槽 9 個子分割槽
create table person8 (name varchar2(20), sex varchar2(10), birth date)
partition by range(birth)
subpartition by list(sex)
subpartition template
(
subpartition sp01 values ('男'),
subpartition sp02 values ('女'),
subpartition sp03 values (default)
)
(
partition p1 values less than (to_date('19900101', 'yyyymmdd')),
partition p2 values less than (to_date('20000101', 'yyyymmdd')),
partition p3 values less than (maxvalue)
);
insert into person8 values ('aaa', '男', to_date('19900202'));
-- 查詢這條資料,有以下三種方式:
select * from person8;
select * from person8 partition (p1);
select * from person8 subpartition (p1_sp01);
範圍-雜湊分割槽:
-- 先按照生日,將資料分為三個區
-- 然後在每個分割槽內,又按照雜湊演算法分成了三個區
-- 這樣就保證了每個分割槽內的資料儘量的少,而且分割槽進行平衡
create table person7 (name varchar2(20), birth date)
partition by range (birth)
subpartition by hash (name) subpartitions 3
(
partition p1 values less than (to_date('19900101', 'yyyymmdd')),
partition p2 values less than (to_date('20000101', 'yyyymmdd')),
partition p3 values less than (maxvalue)
);
相關字典表:
select * from user_objects where object_name ='PERSON8';
select * from user_tables where table_name = 'PERSON8';
select * from user_tab_partitions where table_name = 'PERSON8';
select * from user_tab_subpartitions where table_name = 'PERSON8';
操作表分割槽:
-- 新增分割槽
alter table person add partition p9 values less than (MAXVALUE);
alter table person add partition p9 values (1, 2); -- 針對 list 分割槽
alter table person add partition; -- 針對 hash 分割槽
-- 刪除分割槽
alter table person drop partition p3;
-- 刪除分割槽內資料
alter table person truncate partition p3;
-- 合併相鄰分割槽
alter table person merge partitions p2, p3 into partition p8;
-- 拆分分割槽
alter table person split partition p2 at (3000) into (partition p3, partition p14); -- 範圍分割槽的拆分
alter table person split partition p2 values (1,2) into (partition p3, partition p4); -- 列表分割槽的拆分
alter table person split partition p2 into (partition p3 values (1, 2), partition p4 values (3), partition p5); -- 列表分割槽的拆分
-- 重新命名分割槽
alter table person rename partition p2 to p12;
8.2 物化檢視
以空間換時間
物化檢視,可以看做是 加了同步功能的臨時表,它佔用實際的儲存空間。
建立的物化檢視,可以在 user_tables
字典表裡查到,因為本質上它就是一張表。
如果要建立這樣的臨時表,需要考慮幾個方面:
- 什麼時候初始化資料
build immediate -- 建表的時候順帶初始化資料,預設 build deferred -- 資料延遲建立
- 如果基表中的資料發生變化的時候,以什麼樣的策略保持同步
refresh complete -- 全量重新整理,即將舊的完全刪掉,再重建 refresh fast -- 增量重新整理 refresh force -- 由 Oracle 自動判斷重新整理方式,預設 refresh never -- 不同步資料
- 如果基表中的資料發生變化,資料同步的時機
on commit -- 基本的事務提交立刻同步到物化檢視 on demand start with 開始時間 next 下一個時間 -- 定時同步
- 如果查詢基表中的資料,而這些資料同時包含在物化檢視中,那麼,是不是讓 Oracle 將查詢語句更改為查詢物化檢視
enable query rewrite disable query rewrite -- 預設
建立物化檢視的示例:
-- 建立一個簡單的物化檢視的例子
create materialized view mv_emp1
build immediate -- 建立物化檢視的時候,立刻初始化資料
refresh complete -- 採取全量同步的方式
on commit -- 基表中資料提交會觸發同步行為
-- on demand sysdate next sysdate + 1 -- 每天更新一次
enable query rewrite
as
select * from emp where sal > 3000;
-- 查詢
select * from mv_emp1;
-- 向基表中插入資料
insert into emp (empno, ename, sal) values (8377, '王武', 4444);
-- 事務的提交才會觸發同步,所以這一步不可少
commit;
-- 查詢,看資料是否已經同步
select * from mv_emp1;
-- 如果要增量同步,需要記錄在上次更新到下次更新時間內,基表內所有變化
-- 在這裡,使用的是物化檢視日誌
-- 建立語句如下:
create materialized view log on emp [with rowid/primary key];
-- 然後就可以指定增量同步的方式了
create materialized view mv_emp2
build immediate
refresh fast -- 採取增量同步的方式
on demand sysdate next sysdate + 1 -- 每天更新一次,on demand 後面還有其他很多不同形式的命令
enable query rewrite
as
select * from emp where sal > 3000;
-- 刪除
drop materialized view log on emp;
drop materialized view mv_emp2;
8.3 索引
點陣圖索引示例:
欄位 | 欄位 | 索引 | 索引 | 索引 | 索引 | 索引 | 查詢(xb=女 and hy=否) |
---|---|---|---|---|---|---|---|
XB | HY | xb=男 | xb=女 | xb=未知 | hy=是 | hy=否 | 將兩個索引做與運算 |
男 | 是 | 1 | 0 | 0 | 1 | 0 | 0 |
女 | 是 | 0 | 1 | 0 | 1 | 0 | 0 |
女 | 否 | 0 | 1 | 0 | 0 | 1 | 1(符合條件) |
男 | 是 | 1 | 0 | 0 | 1 | 0 | 0 |
100億 | 100億 | - | - | - | - | - | - |
未知 | 否 | 0 | 0 | 1 | 0 | 1 | 0 |
女 | 是 | 0 | 1 | 0 | 1 | 0 | 0 |