РЕДАКТИРОВАТЬ:
С извинениями мне нужно отозвать свое утверждение о том, что принятый ответ не всегда верен - он утверждает, что представление всегда идентично тому же, что написано в качестве подзапроса. Я думаю, что это неоспоримо, и я думаю, что теперь я знаю, что происходит в моем случае.
Теперь я также думаю, что есть лучший ответ на оригинальный вопрос.
Первоначальный вопрос заключается в том, следует ли руководствоваться практикой использования представлений (в отличие, например, от повторения SQL в подпрограммах, которые, возможно, потребуется поддерживать дважды или более).
Мой ответ будет «нет, если ваш запрос использует оконные функции или что-то еще, что заставляет оптимизатор по-разному относиться к запросу, когда он становится подзапросом, потому что сам процесс создания подзапроса (независимо от того, представлен ли он как представление или нет) может снизить производительность если вы фильтруете с параметрами во время выполнения.
Сложность моей оконной функции не нужна. Объясните план для этого:
SELECT DISTINCT ts.train_service_key,
pc.assembly_key,
count(*) OVER
(PARTITION BY ts.train_service_key) AS train_records
FROM staging.train_service ts
JOIN staging.portion_consist pc
USING (ds_code, train_service_key)
WHERE assembly_key = '185132';
гораздо дешевле, чем для этого:
SELECT *
FROM (SELECT DISTINCT ts.train_service_key,
pc.assembly_key,
count(*) OVER
(PARTITION BY ts.train_service_key) AS train_records
FROM staging.train_service ts
JOIN staging.portion_consist pc
USING (ds_code, train_service_key)) AS query
WHERE assembly_key = '185132';
Надеюсь, это будет более конкретным и полезным.
По моему недавнему опыту (заставляя меня найти этот вопрос), принятый ответ выше не является правильным при всех обстоятельствах. У меня есть относительно простой запрос, который включает в себя функцию окна:
SELECT DISTINCT ts.train_service_key,
pc.assembly_key,
dense_rank() OVER (PARTITION BY ts.train_service_key
ORDER BY pc.through_idx DESC, pc.first_portion ASC,
((CASE WHEN (NOT ts.primary_direction)
THEN '-1' :: INTEGER
ELSE 1
END) * pc.first_seq)) AS coach_block_idx
FROM (staging.train_service ts
JOIN staging.portion_consist pc USING (ds_code, train_service_key))
Если я добавлю этот фильтр:
where assembly_key = '185132'
План объяснения, который я получаю, выглядит следующим образом:
QUERY PLAN
Unique (cost=11562.66..11568.77 rows=814 width=43)
-> Sort (cost=11562.66..11564.70 rows=814 width=43)
Sort Key: ts.train_service_key, (dense_rank() OVER (?))
-> WindowAgg (cost=11500.92..11523.31 rows=814 width=43)
-> Sort (cost=11500.92..11502.96 rows=814 width=35)
Sort Key: ts.train_service_key, pc.through_idx DESC, pc.first_portion, ((CASE WHEN (NOT ts.primary_direction) THEN '-1'::integer ELSE 1 END * pc.first_seq))
-> Nested Loop (cost=20.39..11461.57 rows=814 width=35)
-> Bitmap Heap Scan on portion_consist pc (cost=19.97..3370.39 rows=973 width=38)
Recheck Cond: (assembly_key = '185132'::text)
-> Bitmap Index Scan on portion_consist_assembly_key_index (cost=0.00..19.72 rows=973 width=0)
Index Cond: (assembly_key = '185132'::text)
-> Index Scan using train_service_pk on train_service ts (cost=0.43..8.30 rows=1 width=21)
Index Cond: ((ds_code = pc.ds_code) AND (train_service_key = pc.train_service_key))
При этом используется индекс первичного ключа в таблице обслуживания поездов и неуникальный индекс в таблице part_consist. Выполняется за 90мс.
Я создал представление (вставив его здесь, чтобы быть абсолютно ясным, но это буквально запрос в представлении):
CREATE OR REPLACE VIEW staging.v_unit_coach_block AS
SELECT DISTINCT ts.train_service_key,
pc.assembly_key,
dense_rank() OVER (PARTITION BY ts.train_service_key
ORDER BY pc.through_idx DESC, pc.first_portion ASC, (
(CASE
WHEN (NOT ts.primary_direction)
THEN '-1' :: INTEGER
ELSE 1
END) * pc.first_seq)) AS coach_block_idx
FROM (staging.train_service ts
JOIN staging.portion_consist pc USING (ds_code, train_service_key))
Когда я запрашиваю это представление с идентичным фильтром:
select * from staging.v_unit_coach_block
where assembly_key = '185132';
Это план объяснения:
QUERY PLAN
Subquery Scan on v_unit_coach_block (cost=494217.13..508955.10 rows=3275 width=31)
Filter: (v_unit_coach_block.assembly_key = '185132'::text)
-> Unique (cost=494217.13..500767.34 rows=655021 width=43)
-> Sort (cost=494217.13..495854.68 rows=655021 width=43)
Sort Key: ts.train_service_key, pc.assembly_key, (dense_rank() OVER (?))
-> WindowAgg (cost=392772.16..410785.23 rows=655021 width=43)
-> Sort (cost=392772.16..394409.71 rows=655021 width=35)
Sort Key: ts.train_service_key, pc.through_idx DESC, pc.first_portion, ((CASE WHEN (NOT ts.primary_direction) THEN '-1'::integer ELSE 1 END * pc.first_seq))
-> Hash Join (cost=89947.40..311580.26 rows=655021 width=35)
Hash Cond: ((pc.ds_code = ts.ds_code) AND (pc.train_service_key = ts.train_service_key))
-> Seq Scan on portion_consist pc (cost=0.00..39867.86 rows=782786 width=38)
-> Hash (cost=65935.36..65935.36 rows=1151136 width=21)
-> Seq Scan on train_service ts (cost=0.00..65935.36 rows=1151136 width=21)
Это делает полное сканирование обеих таблиц и занимает 17 секунд.
Пока я не столкнулся с этим, я свободно использовал представления с PostgreSQL (поняв широко распространенные взгляды, выраженные в принятом ответе). Я бы специально избегал использования представлений, если мне нужна предварительная агрегационная фильтрация, для которой я бы использовал функции, возвращающие множество.
Мне также известно, что CTE в PostgreSQL строго оцениваются отдельно, в зависимости от проекта, поэтому я не использую их так же, как с SQL Server, например, где они, кажется, оптимизированы как подзапросы.
Поэтому мой ответ таков: есть случаи, когда представления не работают точно так, как запрос, на котором они основаны, поэтому рекомендуется соблюдать осторожность. Я использую Amazon Aurora на основе PostgreSQL 9.6.6.
SELECT * FROM my_view WHERE my_column = 'blablabla';
:. Второй - об использовании представлений, чтобы сделать вашу модель данных прозрачной для приложения, которое ее использует. Первые источники указывают, что вы должны включить фильтрWHERE my_column = 'blablabla'
в определение представления, так как это приведет к лучшему плану выполнения.