编辑:
对于道歉,我需要撤回断言,即接受的答案并不总是正确的-它指出视图始终与编写为子查询的同一事物相同。我认为这是无可争辩的,我想我现在知道我的情况了。
我现在还认为,对原始问题有更好的答案。
最初的问题是关于是否应该指导使用视图的实践(例如,与在例程中重复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表上的非唯一索引。它在90毫秒内执行。
我创建了一个视图(将其粘贴在此处非常清楚,但这实际上是视图中的查询):
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)
这将对两个表进行全面扫描,并花费17s。
在我遇到这个问题之前,我一直在PostgreSQL中自由使用视图(已经理解了公认的答案中表达的广泛持有的观点)。如果需要预聚合过滤,我特别避免使用视图,为此我将使用集返回功能。
我也知道PostgreSQL中的CTE是通过设计严格进行单独评估的,因此我不会像在SQL Server中那样使用它们,例如,它们似乎已作为子查询进行了优化。
因此,我的回答是,在某些情况下,视图的性能可能不完全符合其所基于的查询,因此建议您格外小心。我正在使用基于PostgreSQL 9.6.6的Amazon Aurora。
SELECT * FROM my_view WHERE my_column = 'blablabla';
。第二个与使用视图使数据模型对使用它的应用程序透明。第一个来源指出您将过滤器包括在WHERE my_column = 'blablabla'
视图定义中,因为这样可以制定更好的执行计划。