แก้ไข:
ด้วยคำขอโทษฉันต้องถอนการยืนยันของฉันว่าคำตอบที่ยอมรับนั้นไม่ถูกต้องเสมอไป - ระบุว่ามุมมองนั้นเหมือนกันเสมอกับสิ่งเดียวกันที่เขียนเป็นแบบสอบถามย่อย ฉันคิดว่ามันเถียงไม่ได้และฉันคิดว่าตอนนี้ฉันรู้ว่าสิ่งที่เกิดขึ้นในกรณีของฉัน
ตอนนี้ฉันก็คิดว่ามีคำตอบที่ดีกว่าสำหรับคำถามเดิม
คำถามเดิมเกี่ยวกับว่ามันควรจะเป็นแนวทางปฏิบัติที่จะใช้มุมมอง (ตรงข้ามกับตัวอย่างเช่นการทำซ้ำ 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))
นี่คือการใช้ดัชนีคีย์หลักในตารางบริการรถไฟและดัชนีที่ไม่ซ้ำกันในตารางส่วนที่ มันดำเนินการใน 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 อย่างอิสระ (ต้องเข้าใจมุมมองที่จัดขึ้นอย่างกว้างขวางที่แสดงในคำตอบที่ยอมรับ) ฉันจะหลีกเลี่ยงการใช้มุมมองเป็นพิเศษหากฉันต้องการการกรองแบบรวมล่วงหน้าซึ่งฉันจะใช้ฟังก์ชั่นการคืนค่า
ฉันยังทราบด้วยว่า CTEs ใน PostgreSQL ได้รับการประเมินแยกต่างหากโดยการออกแบบดังนั้นฉันจึงไม่ใช้มันในวิธีเดียวกับที่ฉันใช้กับ SQL Server ตัวอย่างเช่นที่ซึ่งพวกเขาดูเหมือนจะได้รับการปรับให้เหมาะสมที่สุดในแบบสอบถามย่อย
ดังนั้นคำตอบของฉันคือมีบางกรณีที่มุมมองไม่ทำงานตรงตามคำถามที่พวกเขาใช้ดังนั้นขอแนะนำให้ใช้ความระมัดระวัง ฉันใช้ Amazon Aurora ตาม PostgreSQL 9.6.6
               
              
SELECT * FROM my_view WHERE my_column = 'blablabla';ในขณะที่ตัวที่สองกำลังใช้มุมมองเพื่อทำให้ตัวแบบข้อมูลของคุณโปร่งใสกับแอปพลิเคชันที่ใช้ แหล่งที่มาแรกชี้ให้คุณรวมตัวกรองWHERE my_column = 'blablabla'ในคำจำกัดความของมุมมองเนื่องจากจะทำให้แผนการดำเนินการดีขึ้น