DÜZENLE:
Özür dilerim, kabul edilen cevabın her zaman doğru olmadığı iddiamı geri çekmem gerekiyor - görüşün her zaman bir alt sorgu olarak yazılanla aynı olduğunu söylüyor. Sanırım bu tartışılmaz ve sanırım şu anda davamda neler olup bittiğini biliyorum.
Şimdi asıl sorunun daha iyi bir cevabı olduğunu düşünüyorum.
Asıl soru, görüşlerin kullanılmasının rehberlik etmesi gerekip gerekmediğidir (örneğin, SQL’in iki kez veya daha fazla sürdürülmesi gerekebilecek rutinlerde tekrarlanması yerine).
Cevabım, "sorgunuz pencere işlevlerini veya optimizasyoncunun alt sorgu olduğunda farklı şekilde ele almasına neden olan herhangi bir şey kullanmıyorsa, alt sorguyu oluşturma eylemi (görünüm olarak temsil edilip edilmese de) performansı düşürebilir. Çalışma zamanında parametrelerle filtreleme yapıyorsanız.
Pencere fonksiyonumun karmaşıklığı gereksiz. Bunun için açıklama planı:
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';
bunun için çok daha az maliyetlidir:
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';
Umarım bu biraz daha spesifik ve yardımcı olur.
Son tecrübelerime göre (bu soruyu bulmama neden oluyor), yukarıdaki kabul edilen cevap tüm şartlar altında doğru değil. Pencere işlevini içeren nispeten basit bir sorgu var:
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))
Bu filtreyi eklersem:
where assembly_key = '185132'
Aldığım açıklama planı şöyle:
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))
Bu, tren servis masasındaki birincil anahtar endeksini veuple_consist tablosundaki benzersiz olmayan bir endeksi kullanıyor. 90ms'de çalıştırılır.
Bir görünüm oluşturdum (kesinlikle açık olması için buraya yapıştırarak ancak tam anlamıyla bir görünümdeki sorgu):
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))
Bu görünümü aynı filtreyle sorguladığımda:
select * from staging.v_unit_coach_block
where assembly_key = '185132';
Bu açıklama 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)
Bu iki masada da tam tarama yapıyor ve 17 saniye sürüyor.
Bu konuya gelinceye kadar, libre olarak PostgreSQL ile görüşlerini kullanıyorum (kabul edilen cevapta ifade edilen yaygın görüşlerin anlaşıldığını anladım). Ayar döndürme işlevlerini kullanacağım toplu filtrelemeye ihtiyacım olursa, görünümleri kullanmaktan özellikle kaçınırdım.
Ayrıca PostgreSQL'deki CTE'lerin tasarım açısından kesinlikle ayrı ayrı değerlendirildiğinin farkındayım, bu yüzden bunları SQL Server ile aynı şekilde kullanmıyorum, örneğin alt sorgu olarak optimize edilmiş gibi görünüyorlar.
Bu nedenle cevabım, görüşlerin tam olarak dayandıkları sorgu kadar performans göstermediği durumlar olduğu için dikkatli olunması tavsiye edilir. PostgreSQL 9.6.6 tabanlı Amazon Aurora kullanıyorum.
SELECT * FROM my_view WHERE my_column = 'blablabla';
İkincisi ise veri modelinizi onu kullanan uygulamaya karşı şeffaf yapmak için görünümleri kullanmaktır. İlk kaynaklar, filtreyiWHERE my_column = 'blablabla'
görünüm tanımının içine dahil etmenize işaret eder , çünkü bu daha iyi bir uygulama planı ile sonuçlanır.