SUNTING:
Dengan permintaan maaf, saya perlu menarik kembali pernyataan saya bahwa jawaban yang diterima tidak selalu benar - itu menyatakan bahwa pandangan selalu identik dengan hal yang sama yang ditulis sebagai subquery. Saya pikir itu tidak dapat dibantah, dan saya pikir saya sekarang tahu apa yang terjadi dalam kasus saya.
Saya sekarang juga berpikir ada jawaban yang lebih baik untuk pertanyaan awal.
Pertanyaan aslinya adalah tentang apakah seharusnya membimbing praktik untuk menggunakan pandangan (sebagai lawan, misalnya, mengulangi SQL dalam rutinitas yang mungkin perlu dipertahankan dua kali atau lebih).
Jawaban saya adalah "tidak jika kueri Anda menggunakan fungsi jendela atau apa pun yang menyebabkan pengoptimal memperlakukan kueri secara berbeda ketika menjadi subquery, karena tindakan membuat subquery (apakah diwakili sebagai tampilan atau tidak) dapat menurunkan kinerja jika Anda memfilter dengan parameter saat runtime.
Kompleksitas fungsi jendela saya tidak perlu. Rencana jelaskan untuk ini:
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';
jauh lebih murah daripada ini:
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';
Semoga itu sedikit lebih spesifik dan bermanfaat.
Dalam pengalaman saya baru-baru ini (menyebabkan saya menemukan pertanyaan ini), jawaban yang diterima di atas tidak benar dalam semua keadaan. Saya memiliki permintaan yang relatif sederhana yang mencakup fungsi jendela:
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))
Jika saya menambahkan filter ini:
where assembly_key = '185132'
Rencana jelaskan yang saya dapatkan adalah sebagai berikut:
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))
Ini menggunakan indeks kunci utama pada tabel layanan kereta dan indeks non-unik pada tabel portion_consist. Ini dijalankan dalam 90ms.
Saya membuat tampilan (menempelkannya di sini agar benar-benar jelas tapi secara harfiah kueri dalam tampilan):
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))
Ketika saya menanyakan tampilan ini dengan filter yang identik:
select * from staging.v_unit_coach_block
where assembly_key = '185132';
Ini adalah paket yang jelas:
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)
Ini melakukan pemindaian penuh pada kedua tabel dan membutuhkan 17 detik.
Sampai saya menemukan ini, saya telah bebas menggunakan pandangan dengan PostgreSQL (setelah memahami pandangan yang dipegang secara luas yang dinyatakan dalam jawaban yang diterima). Saya secara khusus akan menghindari menggunakan tampilan jika saya membutuhkan pemfilteran pra-agregat, untuk itu saya akan menggunakan fungsi set-return.
Saya juga menyadari bahwa CTE di PostgreSQL dievaluasi secara terpisah secara terpisah, berdasarkan desain, jadi saya tidak menggunakannya dengan cara yang sama dengan SQL Server, misalnya, di mana mereka tampaknya dioptimalkan sebagai subqueries.
Oleh karena itu, jawaban saya adalah, ada beberapa contoh di mana tampilan tidak berkinerja persis seperti kueri yang menjadi dasarnya, sehingga disarankan untuk berhati-hati. Saya menggunakan Amazon Aurora berdasarkan PostgreSQL 9.6.6.
SELECT * FROM my_view WHERE my_column = 'blablabla';
.Sementara yang kedua adalah tentang menggunakan tampilan untuk membuat model data Anda transparan untuk aplikasi yang menggunakannya. Sumber pertama menunjukkan Anda untuk menyertakan filterWHERE my_column = 'blablabla'
di dalam definisi tampilan, karena ini menghasilkan rencana eksekusi yang lebih baik.