PostgreSQL的物化視圖

9.4英文文檔:http://www.postgresql.org/docs/9.4/interactive/sql-creatematerializedview.html
html

9.3中文文檔:http://www.postgres.cn/docs/9.3/sql-creatematerializedview.htmlsql


概述

    物化視圖是PG9.3新增的,物化視圖既能記住查詢SQL,也能填充數據。後期,還能在須要的時候經過refresh materialized view來實現數據刷新。(注意:目前還不支持在原表數據提交後自動刷新的功能)後端

    refresh materialized view的 concurrently語法是9.4新增的,能夠在刷新視圖時不鎖住對該物化視圖的查詢工做,但在多行受影響時刷新速度會降低;該參數的原理和優缺點與索引的concurrently相似,以時間來換取查詢鎖,刷新的速度會變慢。安全


1、建立物化視圖:

語法:

CREATE MATERIALIZED VIEW table_name
    [ (column_name [, ...] ) ]
    [ WITH ( storage_parameter [= value] [, ... ] ) ]
    [ TABLESPACE tablespace_name ]
    AS query
    [ WITH [ NO ] DATA ]

 是一個PostgreSQL擴展。  函數

 CREATE MATERIALIZED VIEW用來定義一個查詢的物化視圖。在命令發出時,查詢會被執行而且默認用來填充該物化視圖(使用WITH NO DATA則不會填充)。以後能夠經過REFRESH MATERIALIZED VIEW來刷新。post

 物化視圖和表有不少相同的屬性,可是物化視圖不支持臨時物化視圖和自動生更OID(既不支持WITH oid語法)。 ui

   CREATE MATERIALIZED VIEW: 既保存數據,又保存SQL;
spa

   CREATE TABLE AS:只保存數據,不保存sql;.net

   CREATE VIEW:不保存數據,只保存SQL;postgresql

參數:

 table_name:是要建立的物化視圖的名稱(能夠有模式修飾)。

 column_name:物化視圖的列名。若是不提供column_name,將從查詢結果中去獲取。

 storage_parameter:該自居爲物化視圖指定可選的存儲參數。請參照 Storage Parameters 。全部 CREATE TABLE 支持的參數CREATE MATERIALIZED VIEW也都支持,除了OID。請參照 CREATE TABLE

 tablespace_name:指定本物化視圖會被建立到哪一個表空間。若是不指定,則會使用default_tablespace

 query:是一個SELECTTABLE,或者 VALUES 查詢.該查詢將在一個受限制的安全操做中執行。對自身建立臨時表的函數的調用會失敗。

VALUES(1,'lily'); 等價於 select 1, 'lily';
values(1,'lily'),(2,'lucy'); 
等價於 select 1 AS column1,'lily' AS column2 union select 2,'lucy';

TABLE name;等價於 SELECT * FROM name

 WITH [NO] DATA: 聲明物化視圖是否在建立時填充數據。若是不填充的話,該物化視圖將會被標記爲不可掃描的,直到首次REFRESH MATERIALIZED VIEW執行後才能被查詢。

例子:

table=# create table lyy(id int primary key, name varchar);
CREATE TABLE
table=# insert into lyy select generate_series(1,10),'name';
INSERT 0 10
table=# select * from lyy;
 id | name
----+------
  1 | name
  2 | name
.....
(10 rows)
--建立物化視圖with data或者缺省時,物化視圖會被填充,處於可掃描狀態
table=# create materialized view lyy_mv (id, name) as select id,name from lyy;
SELECT 10
table=# select * from lyy_mv;
 id | name
----+------
  1 | name
  2 | name
.....
(10 rows)


2、刷新物化視圖

語法:

REFRESH MATERIALIZED VIEW [ CONCURRENTLY ] name
    [ WITH [ NO ] DATA ]

REFRESH MATERIALIZED VIEW 會徹底替代物化視圖的原有內容,原有內容會被捨棄。若是聲明瞭WITH DATA(或者是缺省),會執行後端查詢來提供新的數據,物化視圖的將保留在可掃描狀態。若是聲明瞭WITH NO DATA,物化視圖將保留在不可掃描的狀態。

CONCURRENTLYWITH NO DATA不能同時使用,不然會報錯

參數:

name:要刷新的物化視圖的名字(能夠有模式修飾)。

CONCURRENTLY:刷新物化視圖而不鎖定物化視圖上的查詢。不指定concurrently選項時,一次影響不少行的刷新,將會使用更少的資源而且完成地更迅速,可是會鎖定其餘試圖從該物化視圖讀數據的連接。該選項在少許行受影響時,可能速度會更快。

        該選項僅在這種狀況下才能使用:在物化視圖上有至少一個UNIQUE索引,Unique索引僅使用列名並涵蓋全部行。也就是說,必須首先建立至少一個,在物化視圖的一個或多個字段上,沒有where子句的,UNIQUE索引,才能使用concurrently選項;不然會報錯。

        在物化視圖未被填充時,不能使用該選項;不然會報錯。

        即便一次運行一個帶有該選項的REFRESH,也可能會與任何一個物化視圖造成競態。

例子:

--原表數據增長後,不刷新物化視圖,物化視圖的數據就不會變
table=# insert into lyy values(11,'lyy');
INSERT 0 1
table=# select * from lyy_mv; 
 id | name
----+------
  1 | name
  2 | name
  ......
  (10 rows)

  
--使用with data或者缺省刷新物化視圖後,新數據會填充,原數據被捨棄
table=# refresh materialized view lyy_mv with data;
REFRESH MATERIALIZED VIEW
table=# select * from lyy_mv;
 id | name
----+------
  1 | name
  2 | name
  ......
 11 |lyy
 (11 rows)
  
  
--使用with no data刷新物化視圖,原數據被捨棄,未填充新數據,將處於不可掃描狀態。
table=# refresh materialized view lyy_mv with no data;
REFRESH MATERIALIZED VIEW
table=# select * from lyy_mv;
ERROR:  materialized view "lyy_mv" has not been populated
detail:  Use the REFRESH MATERIALIZED VIEW command.
--重現刷新物化視圖後,原數據恢復,物化視圖又能夠進行掃描
table=# refresh materialized view lyy_mv;
REFRESH MATERIALIZED VIEW
table=# select * from lyy_mv;
id | name
----+------
  1 | name
  2 | name
  ......
 11 |lyy
 (11 rows)


--必須先建立至少一個unique索引(無where子句,至少涉及一個字段),才能使用concurrently
table=# refresh materialized view concurrently  lyy_mv with data;
ERROR:  cannot refresh materialized view "public.lyy_mv" concurrently
detail:  Create a unique index with no WHERE clause on one or more columns of th
e materialized view.
table=# create unique index lyy_mv_uindex on lyy_mv (id);
CREATE INDEX
table=# refresh materialized view concurrently  lyy_mv with data;
REFRESH MATERIALIZED VIEW


--concurrently與with no data 不能同時使用.
table=# refresh materialized view concurrently  lyy_mv with no data;
ERROR:  CONCURRENTLY and WITH NO DATA options cannot be used together


--物化視圖未被填充時,不能使用concurrently.
table=# refresh materialized view   lyy_mv with no data;
REFRESH MATERIALIZED VIEW
table=# refresh materialized view concurrently  lyy_mv with no data;
ERROR:  CONCURRENTLY cannot be used when the materialized view is not populated


多事務中,物化視圖的普通更新會阻塞對它的查詢,currently更新不會阻塞查詢。

物化視圖的普通更新:

--事務1
table=# begin;
BEGIN
table=# select pg_backend_pid();
 pg_backend_pid
----------------
   3644
table=# refresh materialized view lyy_mv with  data;
REFRESH MATERIALIZED VIEW


--事務2
table=# begin;
BEGIN
table=# select pg_backend_pid();
 pg_backend_pid
----------------
     1316
table=# select pid,mode,relation,granted from pg_locks where relation='lyy_mv'::regclass;
 pid  |        mode         | relation | granted
------+---------------------+----------+---------
 3644 | AccessShareLock     |    74440 | t
 3644 | ShareLock           |    74440 | t
 3644 | ExclusiveLock       |    74440 | t
 3644 | AccessExclusiveLock |    74440 | t
(4 rows)


--事務3
table=# begin;
BEGIN
table=#  select pg_backend_pid();
 pg_backend_pid
----------------
           2772
table=# select * from lyy_mv;
--查詢處於等待狀態


--事務2
table=#  select pid,mode,relation,granted from pg_locks where relation='lyy_mv'::regclass;
 pid  |        mode         | relation | granted
------+---------------------+----------+---------
 2772 | AccessShareLock     |    74440 | f
 3644 | AccessShareLock     |    74440 | t
 3644 | ShareLock           |    74440 | t
 3644 | ExclusiveLock       |    74440 | t
 3644 | AccessExclusiveLock |    74440 | t
(5 rows)

物化視圖的concurrently更新:

--事務1
table=# begin;
BEGIN
table=# select pg_backend_pid();
 pg_backend_pid
----------------
   3644
table=#  refresh materialized view concurrently lyy_mv with  data;
REFRESH MATERIALIZED VIEW


--事務2
table=# begin;
BEGIN
table=#  select pid,mode,relation,granted from pg_locks where relation='lyy_mv':
:regclass;
 pid  |       mode       | relation | granted
------+------------------+----------+---------
 3644 | AccessShareLock  |    74440 | t
 3644 | RowExclusiveLock |    74440 | t
 3644 | ExclusiveLock    |    74440 | t
(3 rows)


--事務3
table=# begin;
BEGIN
table=# select pg_backend_pid();
 pg_backend_pid
----------------
     2772
table=# select * from lyy_mv;
 id | name
----+------
  1 | name
  2 | name
......
 11 | lyy
(11 rows)
--查詢能夠執行,未被阻塞


--事務2
table=#  select pid,mode,relation,granted from pg_locks where relation='lyy_mv'::regclass;
 pid  |       mode       | relation | granted
------+------------------+----------+---------
 2772 | AccessShareLock  |    74440 | t
 3644 | AccessShareLock  |    74440 | t
 3644 | RowExclusiveLock |    74440 | t
 3644 | ExclusiveLock    |    74440 | t
(4 rows)


物化視圖的普通更新要比concurrently更新的效率高不少。

table=# create table yy(id int primary key,name varchar);
CREATE TABLE
table=# create materialized view yy_mv(id,name) as select id, name fro
no data;
SELECT 0
table=# insert into yy(id,name) select generate_series(1,100000),'name
INSERT 0 100000
table=# select count(*) from yy;
 count
--------
 100000
table=# \timing
Time is on.

--普通刷新
table=# refresh materialized view yy_mv with data;
REFRESH MATERIALIZED VIEW
Time: 54.606 ms
table=# select count(*) from yy_mv;
 count
--------
 100000

--concurrently刷新,明顯慢了不少.(此處不考慮數據量很小的狀況)
--首先得爲物化視圖建立無where子句的unique索引。
table=# create unique index yy_mv_uindex on yy_mv(id);
CREATE INDEX
table=# refresh materialized view concurrently yy_mv with data;
REFRESH MATERIALIZED VIEW
TIME: 226.042 ms
table=# select count(*) from yy;
 count
--------
 100000


3、移除物化視圖

語法:

DROP MATERIALIZED VIEW [ IF EXISTS ] name [, ...] [ CASCADE | RESTRICT ]

DROP MATERIALIZED VIEW 刪除已存在的物化視圖。要執行該命令必須是該物化視圖的全部者。

參數:

IF EXISTS : 若是物化視圖不存在不會拋出錯誤,僅發送一個提示信息。

name: 要移除的物化視圖的名稱(能夠有模式修飾)。

CASCADE:自動刪除依賴該物化視圖的對象(好比其餘的物化視圖或者普通視圖)。

RESTRICT : 若是有任何對象依賴於該物化視圖,則拒絕刪除該物化視圖。(這是缺省的)。


參考資料:

http://francs3.blog.163.com/blog/static/405767272014421104127225/

http://my.oschina.net/Kenyon/blog/407093

相關文章
相關標籤/搜索