我们有一个有点复杂的表连接并创建了一个视图,以避免为每次使用编写它。简化......
create view MyView as
select b.id,b.customer_id,b.somedata,t1.moredata
from bigtable b
left join table1 t1 on t1.id=b.t1_id
当它本身使用时,它按预期工作,并在几毫秒内返回行。
select *
from MyView
where customer_id=somevalue -- That's ok
但现实生活并非如此简单。实际上,我们希望将它用作更复杂查询的一部分:
select *
from Customers c
left join MyView v on v.customer_id=c.id
where c.code=somecustomercode -- Simple enough ... but problematic
我们期待快速回答,使用现有索引读取客户表,并在客户已经解决的情况下离开加入视图。
但它需要永远(bigtable有几十万行)。
使用explain
告诉我们原因:首先创建整个视图,然后执行customer表连接作为最后一步。
关于如何改进(使其有效)的任何想法?
已编辑以添加(简化)实际视图以及解释文字。我们正在使用PostgreSQL 9.1.20。实际视图还有两个表更复杂,但这个表有相同的行为。
视图
CREATE OR REPLACE VIEW MyView AS
SELECT trim(ip.res_id, 'res.partner,')::integer AS partner_id,
ppli.product_id,
ppli.fixed_price
FROM ir_property ip
LEFT JOIN product_pricelist ppl ON ppl.id = trim(ip.value_reference, 'product.pricelist,')::integer AND ppl.type = 'c'
LEFT JOIN product_pricelist_item ppli ON ppli.pricelist_id = ppl.id AND ppli.product_id is not null
AND now() between COALESCE(ppli.date_start, '2016-01-01'::date) AND COALESCE(ppli.date_end, '2099-12-31'::date)
WHERE ip.name = 'property_product_pricelist' AND left(ip.res_id, length('res.partner,')) = 'res.partner,'
AND left(ip.value_reference, length('product.pricelist,')) = 'product.pricelist,';
解释使用customer_id直接访问视图的第一个(快速)选择
select *
from MyView
where partner_id=12345
''Nested Loop Left Join (cost=0.01..3920.07 rows=8 width=32)'
' -> Nested Loop Left Join (cost=0.01..3897.79 rows=1 width=24)'
' -> Seq Scan on ir_property ip (cost=0.00..3889.49 rows=1 width=42)'
' Filter: (((name)::text = 'property_product_pricelist'::text) AND ("left"((res_id)::text, 12) = 'res.partner,'::text) AND ("left"((value_reference)::text, 18) = 'product.pricelist,'::text) AND ((btrim((res_id)::text, 'res.partner,'::text))::integer = 128930))'
' -> Index Scan using product_pricelist_pkey on product_pricelist ppl (cost=0.01..8.28 rows=1 width=4)'
' Index Cond: (id = (btrim((ip.value_reference)::text, 'product.pricelist,'::text))::integer)'
' Filter: ((type)::text = 'c'::text)'
' -> Index Scan using product_pricelist_item_pricelist__product_index on product_pricelist_item ppli (cost=0.00..22.06 rows=13 width=16)'
' Index Cond: ((pricelist_id = ppl.id) AND (product_id IS NOT NULL))'
' Filter: ((now() >= COALESCE(date_start, '2016-01-01'::date)) AND (now() <= COALESCE(date_end, '2099-12-31'::date)))'
解释第二个(慢)选择访问视图作为连接
select customer_id,v.*
from res_partner c
left join MyView v on v.partner_id=c.id
where c.ref='Code01'
'Nested Loop Left Join (cost=0.01..3293.42 rows=1 width=1300)'
' Join Filter: ((btrim((ip.res_id)::text, 'res.partner,'::text))::integer = rp.id)'
' -> Index Scan using res_partner_ref_index on res_partner rp (cost=0.00..8.32 rows=1 width=1268)'
' Index Cond: ((ref)::text = 'Code01'::text)'
' -> Nested Loop Left Join (cost=0.01..3284.93 rows=8 width=32)'
' -> Nested Loop Left Join (cost=0.01..3209.33 rows=1 width=24)'
' -> Seq Scan on ir_property ip (cost=0.00..3201.03 rows=1 width=42)'
' Filter: (((name)::text = 'property_product_pricelist'::text) AND ("left"((res_id)::text, 12) = 'res.partner,'::text) AND ("left"((value_reference)::text, 18) = 'product.pricelist,'::text))'
' -> Index Scan using product_pricelist_pkey on product_pricelist ppl (cost=0.01..8.28 rows=1 width=4)'
' Index Cond: (id = (btrim((ip.value_reference)::text, 'product.pricelist,'::text))::integer)'
' Filter: ((type)::text = 'c'::text)'
' -> Index Scan using product_pricelist_item_pricelist__product_index on product_pricelist_item ppli (cost=0.00..75.43 rows=13 width=16)'
' Index Cond: ((pricelist_id = ppl.id) AND (product_id IS NOT NULL))'
' Filter: ((now() >= COALESCE(date_start, '2016-01-01'::date)) AND (now() <= COALESCE(date_end, '2099-12-31'::date)))'