当前位置:   article > 正文

PostgreSQL的物化视图

postgresql物化视图

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

9.3中文文档:http://www.postgres.cn/docs/9.3/sql-creatematerializedview.html


概述

    物化视图是PG9.3新增的,物化视图既能记住查询SQL,也能填充数据。后期,还能在需要的时候通过refresh materialized view来实现数据刷新。(注意:目前还不支持在原表数据提交后自动刷新的功能)

    refresh materialized view的 concurrently语法是9.4新增的,可以在刷新视图时不锁住对该物化视图的查询工作,但在多行受影响时刷新速度会下降;该参数的原理和优缺点与索引的concurrently类似,以时间来换取查询锁,刷新的速度会变慢。


一、创建物化视图:

语法:

  1. CREATE MATERIALIZED VIEW table_name
  2.     [ (column_name [, ...] ) ]
  3.     [ WITH ( storage_parameter [= value] [, ... ] ) ]
  4.     [ TABLESPACE tablespace_name ]
  5.     AS query
  6.     [ WITH [ NO ] DATA ]

 是一个PostgreSQL扩展。  

 CREATE MATERIALIZED VIEW用来定义一个查询的物化视图。在命令发出时,查询会被执行并且默认用来填充该物化视图(使用WITH NO DATA则不会填充)。之后可以通过REFRESH MATERIALIZED VIEW来刷新。

 物化视图和表有很多相同的属性,但是物化视图不支持临时物化视图和自动生更OID(既不支持WITH oid语法)。 

   CREATE MATERIALIZED VIEW: 既保存数据,又保存SQL;

   CREATE TABLE AS:只保存数据,不保存sql;

   CREATE VIEW:不保存数据,只保存SQL;

参数:

 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 查询.该查询将在一个受限制的安全操作中执行。对自身创建临时表的函数的调用会失败。

  1. VALUES(1'lily'); 等价于 select 1'lily';
  2. values(1,'lily'),(2,'lucy'); 
  3. 等价于 select 1 AS column1,'lily' AS column2 union select 2,'lucy';
  4. TABLE name;等价于 SELECT * FROM name

 WITH [NO] DATA: 声明物化视图是否在创建时填充数据。如果不填充的话,该物化视图将会被标记为不可扫描的,直到首次REFRESH MATERIALIZED VIEW执行后才能被查询。

例子:

  1. table=create table lyy(id int primary key, name varchar);
  2. CREATE TABLE
  3. table=insert into lyy select generate_series(1,10),'name';
  4. INSERT 0 10
  5. table=select * from lyy;
  6.  id | name
  7. ----+------
  8.   1 | name
  9.   2 | name
  10. .....
  11. (10 rows
  12. --创建物化视图with data或者缺省时,物化视图会被填充,处于可扫描状态
  13. table=create materialized view lyy_mv (id, name) as select id,name from lyy;
  14. SELECT 10
  15. table=select * from lyy_mv;
  16.  id | name
  17. ----+------
  18.   1 | name
  19.   2 | name
  20. .....
  21. (10 rows


二、刷新物化视图

语法:

  1. REFRESH MATERIALIZED VIEW [ CONCURRENTLY ] name
  2.     [ WITH [ NO ] DATA ]

REFRESH MATERIALIZED VIEW 会完全替代物化视图的原有内容,原有内容会被舍弃。如果声明了WITH DATA(或者是缺省),会执行后端查询来提供新的数据,物化视图的将保留在可扫描状态。如果声明了WITH NO DATA,物化视图将保留在不可扫描的状态。

CONCURRENTLYWITH NO DATA不能同时使用,否则会报错

参数:

name:要刷新的物化视图的名字(可以有模式修饰)。

CONCURRENTLY:刷新物化视图而不锁定物化视图上的查询。不指定concurrently选项时,一次影响很多行的刷新,将会使用更少的资源并且完成地更迅速,但是会锁定其他试图从该物化视图读数据的链接。该选项在少量行受影响时,可能速度会更快。

        该选项仅在这种情况下才能使用:在物化视图上有至少一个UNIQUE索引,Unique索引仅使用列名并涵盖所有行。也就是说,必须首先创建至少一个,在物化视图的一个或多个字段上,没有where子句的,UNIQUE索引,才能使用concurrently选项;否则会报错。

        在物化视图未被填充时,不能使用该选项;否则会报错。

        即使一次运行一个带有该选项的REFRESH,也可能会与任何一个物化视图形成竞态。

例子:

  1. --原表数据增加后,不刷新物化视图,物化视图的数据就不会变
  2. table=insert into lyy values(11,'lyy');
  3. INSERT 0 1
  4. table=select * from lyy_mv; 
  5.  id | name
  6. ----+------
  7.   1 | name
  8.   2 | name
  9.   ......
  10.   (10 rows)
  11.   
  12. --使用with data或者缺省刷新物化视图后,新数据会填充,原数据被舍弃
  13. table=# refresh materialized view lyy_mv with data;
  14. REFRESH MATERIALIZED VIEW
  15. table=select * from lyy_mv;
  16.  id | name
  17. ----+------
  18.   1 | name
  19.   2 | name
  20.   ......
  21.  11 |lyy
  22.  (11 rows
  23.   
  24.   
  25. --使用with no data刷新物化视图,原数据被舍弃,未填充新数据,将处于不可扫描状态。
  26. table=# refresh materialized view lyy_mv with no data;
  27. REFRESH MATERIALIZED VIEW
  28. table=select * from lyy_mv;
  29. ERROR:  materialized view "lyy_mv" has not been populated
  30. detail:  Use the REFRESH MATERIALIZED VIEW command.
  31. --重现刷新物化视图后,原数据恢复,物化视图又可以进行扫描
  32. table=# refresh materialized view lyy_mv;
  33. REFRESH MATERIALIZED VIEW
  34. table=select * from lyy_mv;
  35. id | name
  36. ----+------
  37.   1 | name
  38.   2 | name
  39.   ......
  40.  11 |lyy
  41.  (11 rows
  42. --必须先创建至少一个unique索引(无where子句,至少涉及一个字段),才能使用concurrently
  43. table=# refresh materialized view concurrently  lyy_mv with data;
  44. ERROR:  cannot refresh materialized view "public.lyy_mv" concurrently
  45. detail:  Create a unique index with no WHERE clause on one or more columns of th
  46. e materialized view.
  47. table=create unique index lyy_mv_uindex on lyy_mv (id);
  48. CREATE INDEX
  49. table=# refresh materialized view concurrently  lyy_mv with data;
  50. REFRESH MATERIALIZED VIEW
  51. --concurrently与with no data 不能同时使用.
  52. table=# refresh materialized view concurrently  lyy_mv with no data;
  53. ERROR:  CONCURRENTLY and WITH NO DATA options cannot be used together
  54. --物化视图未被填充时,不能使用concurrently.
  55. table=# refresh materialized view   lyy_mv with no data;
  56. REFRESH MATERIALIZED VIEW
  57. table=# refresh materialized view concurrently  lyy_mv with no data;
  58. ERROR:  CONCURRENTLY cannot be used when the materialized view is not populated


多事务中,物化视图的普通更新会阻塞对它的查询,currently更新不会阻塞查询。

物化视图的普通更新:

  1. --事务1
  2. table=begin;
  3. BEGIN
  4. table=select pg_backend_pid();
  5.  pg_backend_pid
  6. ----------------
  7.    3644
  8. table=# refresh materialized view lyy_mv with  data;
  9. REFRESH MATERIALIZED VIEW
  10. --事务2
  11. table=begin;
  12. BEGIN
  13. table=select pg_backend_pid();
  14.  pg_backend_pid
  15. ----------------
  16.      1316
  17. table=select pid,mode,relation,granted from pg_locks where relation='lyy_mv'::regclass;
  18.  pid  |        mode         | relation | granted
  19. ------+---------------------+----------+---------
  20.  3644 | AccessShareLock     |    74440 | t
  21.  3644 | ShareLock           |    74440 | t
  22.  3644 | ExclusiveLock       |    74440 | t
  23.  3644 | AccessExclusiveLock |    74440 | t
  24. (4 rows)
  25. --事务3
  26. table=begin;
  27. BEGIN
  28. table=#  select pg_backend_pid();
  29.  pg_backend_pid
  30. ----------------
  31.            2772
  32. table=select * from lyy_mv;
  33. --查询处于等待状态
  34. --事务2
  35. table=#  select pid,mode,relation,granted from pg_locks where relation='lyy_mv'::regclass;
  36.  pid  |        mode         | relation | granted
  37. ------+---------------------+----------+---------
  38.  2772 | AccessShareLock     |    74440 | f
  39.  3644 | AccessShareLock     |    74440 | t
  40.  3644 | ShareLock           |    74440 | t
  41.  3644 | ExclusiveLock       |    74440 | t
  42.  3644 | AccessExclusiveLock |    74440 | t
  43. (5 rows

物化视图的concurrently更新:

  1. --事务1
  2. table=begin;
  3. BEGIN
  4. table=select pg_backend_pid();
  5.  pg_backend_pid
  6. ----------------
  7.    3644
  8. table=#  refresh materialized view concurrently lyy_mv with  data;
  9. REFRESH MATERIALIZED VIEW
  10. --事务2
  11. table=begin;
  12. BEGIN
  13. table=#  select pid,mode,relation,granted from pg_locks where relation='lyy_mv':
  14. :regclass;
  15.  pid  |       mode       | relation | granted
  16. ------+------------------+----------+---------
  17.  3644 | AccessShareLock  |    74440 | t
  18.  3644 | RowExclusiveLock |    74440 | t
  19.  3644 | ExclusiveLock    |    74440 | t
  20. (3 rows)
  21. --事务3
  22. table=begin;
  23. BEGIN
  24. table=select pg_backend_pid();
  25.  pg_backend_pid
  26. ----------------
  27.      2772
  28. table=select * from lyy_mv;
  29.  id | name
  30. ----+------
  31.   1 | name
  32.   2 | name
  33. ......
  34.  11 | lyy
  35. (11 rows)
  36. --查询可以执行,未被阻塞
  37. --事务2
  38. table=#  select pid,mode,relation,granted from pg_locks where relation='lyy_mv'::regclass;
  39.  pid  |       mode       | relation | granted
  40. ------+------------------+----------+---------
  41.  2772 | AccessShareLock  |    74440 | t
  42.  3644 | AccessShareLock  |    74440 | t
  43.  3644 | RowExclusiveLock |    74440 | t
  44.  3644 | ExclusiveLock    |    74440 | t
  45. (4 rows)


物化视图的普通更新要比concurrently更新的效率高很多。

  1. table=create table yy(id int primary key,name varchar);
  2. CREATE TABLE
  3. table=create materialized view yy_mv(id,name) as select id, name fro
  4. no data;
  5. SELECT 0
  6. table=insert into yy(id,name) select generate_series(1,100000),'name
  7. INSERT 0 100000
  8. table=# select count(*) from yy;
  9.  count
  10. --------
  11.  100000
  12. table=# \timing
  13. Time is on.
  14. --普通刷新
  15. table=# refresh materialized view yy_mv with data;
  16. REFRESH MATERIALIZED VIEW
  17. Time: 54.606 ms
  18. table=# select count(*) from yy_mv;
  19.  count
  20. --------
  21.  100000
  22. --concurrently刷新,明显慢了很多.(此处不考虑数据量很小的情况)
  23. --首先得为物化视图创建无where子句的unique索引。
  24. table=# create unique index yy_mv_uindex on yy_mv(id);
  25. CREATE INDEX
  26. table=# refresh materialized view concurrently yy_mv with data;
  27. REFRESH MATERIALIZED VIEW
  28. TIME: 226.042 ms
  29. table=# select count(*) from yy;
  30.  count
  31. --------
  32.  100000


三、移除物化视图

语法:

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


转载于:https://my.oschina.net/liuyuanyuangogo/blog/502453

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/601841
推荐阅读
相关标签
  

闽ICP备14008679号