持久性也可以称为耐久性,指的是在事务(不论是提交还是回滚)结束后,DBMS 能够保证该时间点的数据状态会被保存的特性。即使由于系统故障导致数据丢失,数据库也一定能通过某种手段进行恢复(如通过执行日志恢复)。
第 5 章 复杂查询 1、视图 (1)视图跟表的区别使用视图时并不会将数据保存到存储设备之中(正常的表),而且也不会将数据保存到其他任何地方。实际上视图保存的是 SELECT 语句,我们从视图中读取数据时,视图会在内部执行该 SELECT 语句并创建出张临时表。
那么视图和表到底有什么不同呢?区别只有一个,那就是“是否保存了实际的数据”。
(2)优点1、由于视图无需保存数据,因此可以节省存储设备的容量。
2、由于视图保存的只是 SELECT 语句,因此表中的数据更新之后,视图也会自动更新,非常灵活方便。
3、可以将频繁使用的 SELECT 语句保存成视图,这样就不用每次都重新书写了。
(3)创建视图 CREATE VIEW ProductSum (product_type, cnt_product) AS SELECT product_type, COUNT(*) FROM Product GROUP BY product_type;注意:
1、其实可以在视图的基础上再创建新的视图,但是我们还是应该尽量避免。这是因为对多数 DBMS 来说,多重视图会降低 SQL 的性能。推荐使用仅使用单一视图。
2、定义视图时不能使用 ORDER BY 子句(也没有意义,因为”表“数据本来就没有顺序的概念)。
但在 PostgreSQL 中可以。
(4)使用视图1、查询 —— SELECT
SELECT product_type, cnt_product FROM ProductSum;2、(同步)更新 —— INSERT、DELETE、UPDATE
视图和表会同时进行更新。
注意:通过汇总得到的视图无法进行更新,比如视图存在:
SELECT 子句中未使用DISTINCT
FROM 子句中只有一张表
未使用 GROUP BY 子句
未使用 HAVING 子句
PostgreSQL 如果要同步更新,需要事先执行一些语句,有点麻烦,这里略过不赘述了。
(5)删除视图 DROP VIEW ProductSum; -- 如果删除多重视图,可能会因为关联导致删除失败,这时可以使用 CASCADE DROP VIEW ProductSum CASCADE; (6)拓展 - 物化视图上面的视图有个问题,如果没有经过深入思考就定义复杂的视图,可能会带来巨大的性能问题。特别是视图的定义语句中包含以下运算的时候:
聚合函数(AVG、COUNT、SUM、MIN、MAX)
集合运算符(UNION、INTERSECT、EXCEPT 等)
最近越来越多的数据库为了解决视图的这个缺点,实现了物化视图(materialized view)技术。
PostgreSQL v9.3 才支持。
物化视图既真的是一个实实在在存在的表。
创建方法:
CREATE MATERIALIZED VIEW ProductSum (product_type, cnt_product) AS SELECT product_type, COUNT(*) FROM Product GROUP BY product_type;其余方法与普通视图类似,不赘述了。
2、子查询 (1)子查询 概述子查询 就是将用来定义视图的 SELECT 语句直接用于 FROM 子句当中。
可以理解成一张一次性视图,在 SELECT 语句执行之后就消失了。
-- 创建视图 CREATE VIEW ProductSum (product_type, cnt_product) AS SELECT product_type, COUNT(*) FROM Product GROUP BY product_type; -- 使用视图 SELECT product_type, cnt_product FROM ProductSum; -- === 等同于 === -- 子查询 写法 SELECT product_type, cnt_product FROM ( SELECT product_type, COUNT(*) AS cnt_product FROM Product GROUP BY product_type ) AS ProductSum;注意:
子查询作为内层查询会首先执行
子查询可以继续嵌套子查询,甚至无限嵌套下去
为子查询设定名称时需要使用 AS 关键字,该关键字有时也可以省略
(2)标量子查询标量子查询 必须返回表中某一行的某一列的值。
标量就是单一的意思,在数据库之外的领域也经常使用。
应用:由于返回的是单一的值,因此标量子查询可以用在 = 或者 <> 这样需要单一值的比较运算符之中。
-- 错误写法:在 WHERE 子句中不能使用聚合函数 SELECT product_id, product_name, sale_price FROM Product WHERE sale_price > AVG(sale_price); -- 正确写法 SELECT product_id, product_name, sale_price FROM Product WHERE sale_price > (SELECT AVG(sale_price) FROM Product); (3)关联子查询【重难点】问:关联子查询 和 非关联子查询的区别:
答:
非关联子查询:先执行内层查询,再执行外层查询
关联子查询:先执行外层查询,再执行内层查询(内层查询必须引用外层查询的变量)