1. 程式人生 > >效率和速度 --表分割槽,物化檢視,索引

效率和速度 --表分割槽,物化檢視,索引

8.1 表分割槽

分而治之

目的:

  1. 安全(雞蛋不要放在一個籃子裡)
  2. 效率****(快速找到南方it學院所有姓張的人)
  3. 便於維護

場景:

  1. 資料量極大(大於 2G)
  2. 歷史資料比重比較大

分類:

  1. 範圍分割槽
  2. 列表分割槽
  3. 雜湊分割槽(hash)

在以上分割槽的基礎上,可以兩兩結合,形成 複合分割槽,但常用的就是兩種:

  1. 範圍-列表分割槽
  2. 範圍-雜湊分割槽

範圍分割槽:

-- 建立一個普通表的語句
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 字典表裡查到,因為本質上它就是一張表。

如果要建立這樣的臨時表,需要考慮幾個方面:

  1. 什麼時候初始化資料
    build immediate   -- 建表的時候順帶初始化資料,預設
    build deferred    -- 資料延遲建立
    
  2. 如果基表中的資料發生變化的時候,以什麼樣的策略保持同步
    refresh complete  -- 全量重新整理,即將舊的完全刪掉,再重建
    refresh fast      -- 增量重新整理
    refresh force     -- 由 Oracle 自動判斷重新整理方式,預設
    refresh never     -- 不同步資料
    
  3. 如果基表中的資料發生變化,資料同步的時機
    on commit         -- 基本的事務提交立刻同步到物化檢視
    on demand start with 開始時間 next 下一個時間  -- 定時同步
    
  4. 如果查詢基表中的資料,而這些資料同時包含在物化檢視中,那麼,是不是讓 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