BEARBEITEN:
Mit Entschuldigung muss ich meine Behauptung zurückziehen, dass die akzeptierte Antwort nicht immer korrekt ist - es heißt, dass die Ansicht immer mit der gleichen Sache identisch ist, die als Unterabfrage geschrieben wurde. Ich denke, das ist unbestreitbar, und ich glaube jetzt zu wissen, was in meinem Fall vor sich geht.
Ich denke jetzt auch, dass es eine bessere Antwort auf die ursprüngliche Frage gibt.
Die ursprüngliche Frage ist, ob die Verwendung von Ansichten als Richtschnur dienen sollte (im Gegensatz zum Beispiel zum Wiederholen von SQL in Routinen, die möglicherweise zweimal oder öfter verwaltet werden müssen).
Meine Antwort wäre "nicht, wenn Ihre Abfrage Fensterfunktionen oder andere Funktionen verwendet, die das Optimierungsprogramm veranlassen, die Abfrage anders zu behandeln, wenn sie zu einer Unterabfrage wird, da das Erstellen der Unterabfrage (unabhängig davon, ob sie als Ansicht dargestellt wird oder nicht) die Leistung beeinträchtigen kann Wenn Sie zur Laufzeit mit Parametern filtern.
Die Komplexität meiner Fensterfunktion ist unnötig. Der Erklärungsplan dazu:
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';
ist viel günstiger als hierfür:
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';
Hoffe, das ist ein bisschen genauer und hilfreich.
Nach meinen jüngsten Erfahrungen (die mich veranlassen, diese Frage zu finden) ist die oben akzeptierte Antwort nicht unter allen Umständen korrekt. Ich habe eine relativ einfache Abfrage, die eine Fensterfunktion enthält:
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))
Wenn ich diesen Filter hinzufüge:
where assembly_key = '185132'
Der Erklärungsplan, den ich erhalte, lautet wie folgt:
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))
Hierbei wird der Primärschlüsselindex für die Train Service-Tabelle und ein nicht eindeutiger Index für die portion_consist-Tabelle verwendet. Es wird in 90 ms ausgeführt.
Ich habe eine Ansicht erstellt (hier einfügen, um die Übersichtlichkeit zu verdeutlichen, aber es ist buchstäblich die Abfrage in einer Ansicht):
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))
Wenn ich diese Ansicht mit dem identischen Filter abfrage:
select * from staging.v_unit_coach_block
where assembly_key = '185132';
Dies ist der EXPLAIN-Plan:
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)
Dies führt vollständige Scans an beiden Tischen durch und dauert 17 Sekunden.
Bis ich darauf stieß, habe ich Ansichten mit PostgreSQL großzügig genutzt (nachdem ich die weit verbreiteten Ansichten verstanden hatte, die in der akzeptierten Antwort zum Ausdruck kamen). Ich würde speziell die Verwendung von Ansichten vermeiden, wenn ich eine Vor-Aggregat-Filterung benötige, für die ich Set-Return-Funktionen verwenden würde.
Mir ist auch bewusst, dass CTEs in PostgreSQL strikt getrennt ausgewertet werden, sodass ich sie nicht so verwende, wie ich es zum Beispiel mit SQL Server tun würde, wo sie als Unterabfragen optimiert zu sein scheinen.
Meine Antwort lautet daher, dass es Fälle gibt, in denen Ansichten nicht genau so ausgeführt werden, wie die Abfrage, auf der sie basieren. Daher ist Vorsicht geboten. Ich benutze Amazon Aurora basierend auf PostgreSQL 9.6.6.
SELECT * FROM my_view WHERE my_column = 'blablabla';
danach auf das Anwenden eines Filters: In der zweiten werden Ansichten verwendet, um das Datenmodell für die Anwendung, die es verwendet, transparent zu machen. Die erste Quelle weist Sie darauf hin, den FilterWHERE my_column = 'blablabla'
in die Ansichtsdefinition aufzunehmen, da dies zu einem besseren Ausführungsplan führt.