2010-07-02 38 views
0

它看起來像從執行計劃的版本快於EXISTS版本如何解釋這個執行計劃(IN vs EXISTS)?

我想存在的查詢速度更快,因爲它急切地檢查的條件。 IN查詢雖然看起來很直觀,但我覺得它似乎很晚就解決了最終條件的結果;即從內向外,我發現IN較慢,因爲下一個條件需要等待的內部條件的結果。

雖然從下面的執行計劃看,IN更快;它具有較低的成本。

我的一部分想要使用IN版本,它對於下一個維護者來說看起來簡單直觀,下面的執行計劃似乎表明它比EXISTS更快。但我的另一部分人想要使用EXISTS,因爲我覺得它更快,但下面的執行計劃似乎與這種看法相矛盾。

下面兩個查詢中哪個更快,是IN版本還是EXISTS版本?

版本:

explain analyze 
select ceil( 
     (count(distinct company_rec_id)::numeric + 1) 
     /((1)))::int 
from 
parcel ord 
join company c on c.company_rec_id = ord.client_rec_id 

where 
    (
     (((E'')) <> '' and to_tsvector(c.company) @@ plainto_tsquery(extract_words(((E''))))) 
     or ((E'')) = '' 
    ) 

    and 
    (
     (((0)) <> 0 and ord.parcel_number = ((0))) 
     or ((0)) = 0 
    ) 


    and parcel_rec_id in 
    (
     select parcel_rec_id 
     from parcel_application 
     where parcel_application_rec_id in 
     (
      select parcel_application_rec_id 
      from parcel_application_shoe 
      where    
       (
       (((E'')) <> '' and to_tsvector(extract_words(shoe_description)) @@ plainto_tsquery(extract_words(((E''))))) 
       or ((E'')) = '' 
       ) 

       and 
       (
       (((E'')) <> '' and to_tsvector(extract_words(order_number)) @@ plainto_tsquery(extract_words(((E''))))) 
       or ((E'')) = '' 
       ) 


       and 
       (
       (((E'')) <> '' and to_tsvector(extract_words(style_number)) @@ plainto_tsquery(extract_words(((E''))))) 
       or ((E'')) = '' 
       )    
     ) 
    ) 

"Aggregate (cost=1060.73..1060.75 rows=1 width=37) (actual time=29.028..29.028 rows=1 loops=1)" 
" -> Hash Join (cost=880.43..1053.04 rows=3074 width=37) (actual time=13.261..16.365 rows=3074 loops=1)" 
"  Hash Cond: ((ord.client_rec_id)::text = (c.company_rec_id)::text)" 
"  -> Hash Join (cost=864.79..995.14 rows=3074 width=37) (actual time=13.115..15.027 rows=3074 loops=1)" 
"    Hash Cond: ((ord.parcel_rec_id)::text = (parcel_application.parcel_rec_id)::text)" 
"    -> Seq Scan on parcel ord (cost=0.00..78.87 rows=3087 width=74) (actual time=0.005..0.373 rows=3087 loops=1)" 
"    -> Hash (cost=826.37..826.37 rows=3074 width=37) (actual time=13.102..13.102 rows=3074 loops=1)" 
"     -> HashAggregate (cost=795.63..826.37 rows=3074 width=37) (actual time=11.835..12.281 rows=3074 loops=1)" 
"       -> Hash Join (cost=541.34..787.59 rows=3218 width=37) (actual time=7.076..10.286 rows=3218 loops=1)" 
"        Hash Cond: ((parcel_application.parcel_application_rec_id)::text = (parcel_application_shoe.parcel_application_rec_id)::text)" 
"        -> Seq Scan on parcel_application (cost=0.00..122.18 rows=3218 width=74) (actual time=0.004..0.710 rows=3218 loops=1)" 
"        -> Hash (cost=501.12..501.12 rows=3218 width=37) (actual time=7.061..7.061 rows=3218 loops=1)" 
"          -> HashAggregate (cost=468.94..501.12 rows=3218 width=37) (actual time=5.721..6.220 rows=3218 loops=1)" 
"           -> Seq Scan on parcel_application_shoe (cost=0.00..442.95 rows=10395 width=37) (actual time=0.004..2.318 rows=10395 loops=1)" 
"  -> Hash (cost=11.95..11.95 rows=295 width=37) (actual time=0.136..0.136 rows=295 loops=1)" 
"    -> Seq Scan on company c (cost=0.00..11.95 rows=295 width=37) (actual time=0.013..0.068 rows=295 loops=1)" 
"Total runtime: 29.122 ms" 

EXISTS版本:

explain analyze 
select ceil( 
      (count(distinct company_rec_id)::numeric + 1) 
      /((1)))::int from 

parcel ord 
join company c on c.company_rec_id = ord.client_rec_id 
where 

    (
     (((E'')) <> '' and to_tsvector(c.company) @@ plainto_tsquery(extract_words(((E''))))) 
     or ((E'')) = '' 
    ) 

    and 
    (
     (((0)) <> 0 and ord.parcel_number = ((0))) 
     or ((0)) = 0 
    ) 


    and exists 
    (
     select * from parcel_application pa  
     where pa.parcel_rec_id = ord.parcel_rec_id 

      and 
      exists 
      (
       select * from parcel_application_shoe ord_item 
       where 
        ord_item.parcel_application_rec_id = pa.parcel_application_rec_id 

        and   
        (
        (((E'')) <> '' and to_tsvector(extract_words(ord_item.shoe_description)) @@ plainto_tsquery(extract_words(((E''))))) 
        or ((E'')) = '' 
        ) 

        and 
        (
        (((E'')) <> '' and to_tsvector(extract_words(ord_item.order_number)) @@ plainto_tsquery(extract_words(((E''))))) 
        or ((E'')) = '' 
        ) 


        and 
        (
        (((E'')) <> '' and to_tsvector(extract_words(ord_item.style_number)) @@ plainto_tsquery(extract_words(((E''))))) 
        or ((E'')) = '' 
        ) 



      ) 
    ) 


"Aggregate (cost=17773.13..17773.16 rows=1 width=37) (actual time=34.519..34.520 rows=1 loops=1)" 
" -> Hash Join (cost=17636.59..17769.11 rows=1609 width=37) (actual time=17.174..20.426 rows=3074 loops=1)" 
"  Hash Cond: ((ord.client_rec_id)::text = (c.company_rec_id)::text)" 
"  -> Hash Join (cost=17620.95..17731.35 rows=1609 width=37) (actual time=16.882..18.862 rows=3074 loops=1)" 
"    Hash Cond: ((ord.parcel_rec_id)::text = (pa.parcel_rec_id)::text)" 
"    -> Seq Scan on parcel ord (cost=0.00..78.87 rows=3087 width=74) (actual time=0.006..0.409 rows=3087 loops=1)" 
"    -> Hash (cost=17601.74..17601.74 rows=1537 width=37) (actual time=16.858..16.858 rows=3074 loops=1)" 
"     -> HashAggregate (cost=17586.37..17601.74 rows=1537 width=37) (actual time=15.015..15.535 rows=3074 loops=1)" 
"       -> Seq Scan on parcel_application pa (cost=0.00..17582.35 rows=1609 width=37) (actual time=10.040..12.440 rows=3218 loops=1)" 
"        Filter: (alternatives: SubPlan 1 or hashed SubPlan 2)" 
"        SubPlan 1" 
"         -> Index Scan using fki_parcel_application_shoe__parcel_application on parcel_application_shoe ord_item (cost=0.00..16.28 rows=3 width=0) (never executed)" 
"          Index Cond: ((parcel_application_rec_id)::text = ($0)::text)" 
"        SubPlan 2" 
"         -> Seq Scan on parcel_application_shoe ord_item (cost=0.00..442.95 rows=10395 width=37) (actual time=0.005..4.482 rows=10395 loops=1)" 
"  -> Hash (cost=11.95..11.95 rows=295 width=37) (actual time=0.284..0.284 rows=295 loops=1)" 
"    -> Seq Scan on company c (cost=0.00..11.95 rows=295 width=37) (actual time=0.010..0.155 rows=295 loops=1)" 
"Total runtime: 34.645 ms" 

這是最終的查詢我最終使用時,IN版本。我只能看到 IN和EXISTS版本之間的邊際性能差異。我想詳細瞭解可讀性下一個維護者,所以我用IN

select ord.parcel_number, ord.received_date, c.company 
from parcel ord 
join company c on c.company_rec_id = ord.client_rec_id 

where 

    (
     :_company = '' 
     or 
     to_tsvector(c.company) @@ plainto_tsquery(extract_words(:_company)) 
    ) 

    and 
    (
     :_fttsc_num = 0 
     or ord.parcel_number = :_fttsc_num   
    ) 




and 
(
    (:_item = '' and :_order_num = '' and :_style_num = '') 


    or 

    ord.parcel_rec_id in 
    (
     select parcel_rec_id 
     from parcel_application 
     where parcel_application_rec_id in 
      (

       select parcel_application_rec_id 
       from parcel_application_shoe 
       where 

        (
         :_item = '' 
         or to_tsvector(extract_words(shoe_description)) @@ plainto_tsquery(extract_words(:_item))       
        ) 

        and 
        (
         :_order_num = '' 
         or to_tsvector(extract_words(order_number)) @@ plainto_tsquery(extract_words(:_order_num))       
        ) 


        and 
        (
         :_style_num = '' 
         or to_tsvector(extract_words(style_number)) @@ plainto_tsquery(extract_words(:_style_num))      
        ) 

      ) -- parcel_application_rec_id IN 
    ) -- parcel_rec_id IN 
) 

and 

-- material filter... 
(
    (:_material = '') 

    or 

    -- implied material <> '' 
    parcel_rec_id in 
    (
     select parcel_rec_id 
     from parcel_application 
     where parcel_application_rec_id in 
      (
       select parcel_application_rec_id 
       from mlist 
       where mlist_rec_id in 
        (
         select mlist_rec_id 
         from mlist_detail 
         join material m using(material_rec_id) 
         where to_tsvector(extract_words(m.material)) @@ plainto_tsquery(extract_words(:_material)) 
        ) 
      ) 
    ) 

) 
-- ...material filter 

and 

-- parameter filter... 
(
    (:_parameter = '') 

    or 

    -- implied parameter <> '' 
    parcel_rec_id in 
    (
     select parcel_rec_id 
     from parcel_application 
     where parcel_application_rec_id in 
      (
       select parcel_application_rec_id 
       from mlist 
       where mlist_rec_id in 
        (
         select mlist_rec_id 
         from mlist_detail 
         where mlist_detail_rec_id in 
          (
           select mlist_detail_rec_id 
           from mlist_detail_parameter 
           join parameter p using(parameter_rec_id) 
           where to_tsvector(extract_words(p.parameter)) @@ plainto_tsquery(extract_words(:_parameter)) 
          ) 
        ) 
      ) 
    ) 

) 
-- ...parameter filter 

order by ord.received_date 
+0

你可以添加的EXPLAIN分析的結果? – 2010-07-02 07:23:41

+0

@Frank Heikens:很難獲得總運行時間,他們總是起伏不大,差別不大。但EXISTS似乎更快,每次運行10次,EXISTS進行5次的時間少於30毫秒;而與IN,只有一次 – 2010-07-02 08:18:27

+0

我沒有要求的運行時間,但執行計劃。我假設你之前做過VACUUM ANALYZE,只要確保統計數據是最新的。 – 2010-07-02 08:31:01

回答

1

你可能要重新審視這組嵌套EXISTS()子查詢。 In the past看來,使用這些表現不如在內連接上具有單個EXISTS。

所以在一般情況下,變換是這樣的:

where exists (select 1 from foo join bar using (foo_id) 
       where foo.outer_id = outer.outer_id)