편집하다:
사과를 통해 받아 들인 대답이 항상 정확하지는 않다는 주장을 철회해야합니다.보기는 항상 하위 쿼리로 작성된 것과 동일하다는 것을 나타냅니다. 나는 그것이 논쟁의 여지가 없다고 생각하며, 나는 지금 내 사건에서 무슨 일이 일어나고 있는지 알고 있다고 생각합니다.
나는 또한 원래 질문에 대한 더 나은 대답이 있다고 생각합니다.
원래 질문은 뷰를 사용하는 연습을 안내해야하는지에 관한 것입니다 (예를 들어, 두 번 이상 유지해야하는 루틴에서 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 테이블의 고유하지 않은 인덱스를 사용하고 있습니다. 90ms에서 실행됩니다.
뷰를 만들었습니다 (절대적으로 명확하게 붙여 넣지 만 실제로는 뷰의 쿼리입니다).
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과 함께 뷰를 자유롭게 사용했습니다 (허용 된 답변으로 표현 된 광범위한 견해를 이해하게 함). 사전 집계 필터링이 필요한 경우 뷰 반환 기능을 사용하는 경우보기를 사용하지 않는 것이 좋습니다.
또한 PostgreSQL의 CTE는 설계 상 엄격하게 별도로 평가되므로 하위 쿼리로 최적화 된 것처럼 SQL Server와 같은 방식으로 사용하지 않습니다.
따라서 내 대답은 뷰가 기반으로하는 쿼리와 정확히 일치하지 않는 경우가 있으므로주의를 기울이는 것이 좋습니다. PostgreSQL 9.6.6 기반 Amazon Aurora를 사용하고 있습니다.
SELECT * FROM my_view WHERE my_column = 'blablabla';
. 두 번째는 뷰를 사용하여 데이터 모델을 사용하는 응용 프로그램에 데이터 모델을 투명하게 만드는 것입니다. 첫 번째 소스WHERE my_column = 'blablabla'
는 뷰 정의 내에 필터를 포함하도록 지시 하므로 실행 계획이 향상됩니다.