表定义+样本数据:
\i tmp.sql
CREATE table eee
( form_id SERIAL NOT NULL PRIMARY KEY
, payload char (500)
);
INSERT INTO eee(payload)
SELECT 'payload_'|| gs::text
FROM generate_series(1,100) gs;
CREATE table ddd
( id SERIAL NOT NULL PRIMARY KEY
, form_id SERIAL NOT NULL REFERENCES eee(form_id)
, fld char (100)
, val char (200)
, trash char (400)
, filth char (800)
);
CREATE INDEX ON ddd(form_id);
INSERT INTO ddd(form_id, fld,val,trash,filth)
SELECT eee.form_id
, 'fld_'|| gs::text
, 'val_'|| gs::text
, 'trash_'|| gs::text
, 'filth_'|| gs::text
FROM eee
JOIN generate_series(1,10) gs ON random() < 0.3
;
VACUUM ANALYZE eee;
VACUUM ANALYZE ddd;
两个视图:
CREATE VIEW v1 AS
SELECT e.form_id
, d.fld, d.val
FROM eee e
JOIN ddd d ON d.form_id = e.form_id
;
CREATE VIEW v0 AS
SELECT e.payload
, d.*
FROM eee e
JOIN ddd d ON d.form_id = e.form_id
;
让我们试试吧:
\echo v1 complete
EXPLAIN SELECT * FROM v1 ;
\echo v1 three fields
EXPLAIN SELECT form_id,fld, val FROM v1 ;
\echo v0 complete
EXPLAIN SELECT * FROM v0 ;
\echo v0 three fields
EXPLAIN SELECT form_id,fld, val FROM v0 ;
\echo v0 four fields
EXPLAIN SELECT form_id,fld, val,trash FROM v0 ;
输出:
DROP SCHEMA
CREATE SCHEMA
SET
CREATE TABLE
INSERT 0 100
CREATE TABLE
CREATE INDEX
INSERT 0 309
VACUUM
VACUUM
CREATE VIEW
CREATE VIEW
v1 complete
QUERY PLAN
-----------------------------------------------------------------------------------------
Hash Join (cost=5.09..71.03 rows=309 width=309)
Hash Cond: (d.form_id = e.form_id)
-> Seq Scan on ddd d (cost=0.00..65.09 rows=309 width=309)
-> Hash (cost=3.84..3.84 rows=100 width=4)
-> Index Only Scan using eee_pkey on eee e (cost=0.14..3.84 rows=100 width=4)
(5 rows)
v1 three fields
QUERY PLAN
-----------------------------------------------------------------------------------------
Hash Join (cost=5.09..71.03 rows=309 width=309)
Hash Cond: (d.form_id = e.form_id)
-> Seq Scan on ddd d (cost=0.00..65.09 rows=309 width=309)
-> Hash (cost=3.84..3.84 rows=100 width=4)
-> Index Only Scan using eee_pkey on eee e (cost=0.14..3.84 rows=100 width=4)
(5 rows)
v0 complete
QUERY PLAN
---------------------------------------------------------------------
Hash Join (cost=9.25..75.18 rows=309 width=2025)
Hash Cond: (d.form_id = e.form_id)
-> Seq Scan on ddd d (cost=0.00..65.09 rows=309 width=1521)
-> Hash (cost=8.00..8.00 rows=100 width=508)
-> Seq Scan on eee e (cost=0.00..8.00 rows=100 width=508)
(5 rows)
v0 three fields
QUERY PLAN
-----------------------------------------------------------------------------------------
Hash Join (cost=5.09..71.03 rows=309 width=309)
Hash Cond: (d.form_id = e.form_id)
-> Seq Scan on ddd d (cost=0.00..65.09 rows=309 width=309)
-> Hash (cost=3.84..3.84 rows=100 width=4)
-> Index Only Scan using eee_pkey on eee e (cost=0.14..3.84 rows=100 width=4)
(5 rows)
v0 four fields
QUERY PLAN
-----------------------------------------------------------------------------------------
Hash Join (cost=5.09..71.03 rows=309 width=713)
Hash Cond: (d.form_id = e.form_id)
-> Seq Scan on ddd d (cost=0.00..65.09 rows=309 width=713)
-> Hash (cost=3.84..3.84 rows=100 width=4)
-> Index Only Scan using eee_pkey on eee e (cost=0.14..3.84 rows=100 width=4)
(5 rows)
现在看看计划中的“宽度”列:它们不同,不仅取决于表和视图定义,还取决于最终查询。
这是因为,在 postgres 中,视图是一种宏:它被合并到查询计划中**在*发生任何优化之前。之后的优化器会从计划中删除未引用的列,从而减少结果的行大小。
从基表读取的数据量当然是相同的:物理表没有改变它们的行大小。
非内部人士注意:我故意使用CHAR(xxx) 列来扩大行大小。 varchar() 列会被烘烤。 (:=放入辅助存储),并且不会夸大行大小。