Определения таблиц + примеры данных:
\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()
колонны были бы поджарены. (: = поместить во вторичное хранилище), и НЕ будет раздувать размеры строк.