BIÊN TẬP:
Với lời xin lỗi, tôi cần rút lại khẳng định của mình rằng câu trả lời được chấp nhận không phải lúc nào cũng đúng - nó nói rằng quan điểm luôn giống hệt với điều tương tự được viết như một câu hỏi phụ. Tôi nghĩ đó là điều không thể chối cãi, và tôi nghĩ bây giờ tôi biết những gì đang xảy ra trong trường hợp của tôi.
Bây giờ tôi cũng nghĩ rằng có một câu trả lời tốt hơn cho câu hỏi ban đầu.
Câu hỏi ban đầu là về việc có nên hướng dẫn thực hành sử dụng các khung nhìn hay không (ví dụ, lặp lại SQL trong các thói quen có thể cần được duy trì hai lần trở lên).
Câu trả lời của tôi sẽ là "không phải nếu truy vấn của bạn sử dụng các chức năng của cửa sổ hay bất cứ điều gì khác khiến trình tối ưu hóa xử lý truy vấn khác nhau khi nó trở thành truy vấn phụ, bởi vì chính hành động tạo truy vấn con (dù được biểu thị dưới dạng xem hay không) có thể làm giảm hiệu suất nếu bạn đang lọc với các tham số trong thời gian chạy.
Sự phức tạp của chức năng cửa sổ của tôi là không cần thiết. Kế hoạch giải thích cho việc này:
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';
ít tốn kém hơn nhiều so với việc này:
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';
Hy vọng đó là một chút cụ thể và hữu ích.
Theo kinh nghiệm gần đây của tôi (khiến tôi tìm thấy câu hỏi này), câu trả lời được chấp nhận ở trên không chính xác trong tất cả các chu kỳ. Tôi có một truy vấn tương đối đơn giản bao gồm chức năng cửa sổ:
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))
Nếu tôi thêm bộ lọc này:
where assembly_key = '185132'
Kế hoạch giải thích tôi nhận được như sau:
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))
Điều này đang sử dụng chỉ mục khóa chính trên bảng dịch vụ xe lửa và chỉ mục không duy nhất trên bảng part_consist. Nó thực thi trong 90ms.
Tôi đã tạo một chế độ xem (dán nó ở đây để hoàn toàn rõ ràng nhưng đó thực sự là truy vấn trong một chế độ xem):
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))
Khi tôi truy vấn chế độ xem này với bộ lọc giống hệt nhau:
select * from staging.v_unit_coach_block
where assembly_key = '185132';
Đây là kế hoạch giải thích:
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)
Điều này đang thực hiện quét toàn bộ trên cả hai bảng và mất 17 giây.
Cho đến khi tôi bắt gặp điều này, tôi đã tự do sử dụng các khung nhìn với PostgreSQL (đã hiểu các quan điểm được tổ chức rộng rãi thể hiện trong câu trả lời được chấp nhận). Tôi đặc biệt tránh sử dụng các chế độ xem nếu tôi cần lọc tổng hợp trước, trong đó tôi sử dụng các hàm trả về cài đặt.
Tôi cũng biết rằng các CTE trong PostgreSQL được đánh giá riêng biệt, theo thiết kế, vì vậy tôi không sử dụng chúng theo cách tương tự như với SQL Server, ví dụ, nơi chúng dường như được tối ưu hóa như các truy vấn con.
Do đó, câu trả lời của tôi là, có những trường hợp trong đó các khung nhìn không thực hiện chính xác như truy vấn mà chúng dựa trên, vì vậy nên thận trọng. Tôi đang sử dụng Amazon Aurora dựa trên PostgreQuery 9.6.6.
SELECT * FROM my_view WHERE my_column = 'blablabla';
. Trong khi thứ hai là về việc sử dụng các khung nhìn để làm cho mô hình dữ liệu của bạn trong suốt đối với ứng dụng sử dụng nó. Các nguồn đầu tiên chỉ cho bạn bao gồm bộ lọcWHERE my_column = 'blablabla'
bên trong định nghĩa khung nhìn, vì điều này dẫn đến một kế hoạch thực hiện tốt hơn.