Postgresql 9.2 - 为什么速度差异 - SQL Subselect和JOIN?

时间:2016-11-18 22:56:15

标签: postgresql subquery postgresql-9.2

我正在尝试查询另一个软件的数据库,所以我无法控制索引,函数等。我有只读访问权限,所以我不相信我甚至可以创建一个临时表。我只是无法理解为什么会有差异。

这是我的基本查询:

WITH vCriteria AS (
    SELECT vSub.visit_id, vd.vdiag_diag from visit vSUB  
    JOIN insurance_company_table1 inscomp1 ON inscomp1.inscomp1_comp = vSub.visit_ins 
        and inscomp1.inscomp1_arid = vSub.visit_arid
    JOIN da152 da ON da.da152_arid = vSub.visit_arid 
    LEFT JOIN insurance1 i ON i.is1_num = vSub.visit_id AND i.is1_ins_full = vSub.visit_ins
    LEFT JOIN visit_diagnosis vd ON vd.vdiag_visit_key = vSub.visit_id

    WHERE vSub.visit_mr_fdt 
    BETWEEN (now() - 50 * INTERVAL '1 day') AND (now() + 10 * INTERVAL '1 day') 
    AND NULLIF (vSub.visit_disch_date, '0001-01-01' ::date) IS NOT NULL 
    AND Now() >=(vSub.visit_disch_date + inscomp1.inscomp1_lagdays * INTERVAL '1 day') 
    AND vSub.visit_servicecd_key ~ '^[0-9]+$|[FHJbKkN\\+]' = false 
    AND LEFT (vSub.visit_id, 1) NOT IN ('F', 'P', 'J') 
    AND NULLIF (i.is1_bill_dt, '0001-01-01' ::date) IS NULL 
    AND vSub.visit_disch_date <= da.da152_chgdt
) 

Select vCriteria.* from vCriteria

它在609 ms内执行

我添加1个连接,需要更长的时间: LEFT JOIN visit_diagnosis vd ON vd.vdiag_visit_key = vSub.visit_id

WITH vCriteria AS (
    SELECT vSub.visit_id, vd.vdiag_diag from visit vSUB  
    JOIN insurance_company_table1 inscomp1 ON inscomp1.inscomp1_comp = vSub.visit_ins 
        and inscomp1.inscomp1_arid = vSub.visit_arid
    JOIN da152 da ON da.da152_arid = vSub.visit_arid 
    LEFT JOIN insurance1 i ON i.is1_num = vSub.visit_id AND i.is1_ins_full = vSub.visit_ins
   LEFT JOIN visit_diagnosis vd ON vd.vdiag_visit_key = vSub.visit_id

    WHERE vSub.visit_mr_fdt 
    BETWEEN (now() - 50 * INTERVAL '1 day') AND (now() + 10 * INTERVAL '1 day') 
    AND NULLIF (vSub.visit_disch_date, '0001-01-01' ::date) IS NOT NULL 
    AND Now() >=(vSub.visit_disch_date + inscomp1.inscomp1_lagdays * INTERVAL '1 day') 
    AND vSub.visit_servicecd_key ~ '^[0-9]+$|[FHJbKkN\\+]' = false 
    AND LEFT (vSub.visit_id, 1) NOT IN ('F', 'P', 'J') 
    AND NULLIF (i.is1_bill_dt, '0001-01-01' ::date) IS NULL 
    AND vSub.visit_disch_date <= da.da152_chgdt
) 

Select vCriteria.* from vCriteria

执行

需要13秒

因此,上面的查询非常简化,这里是我试过的例子。 如果我做这样的事情:

SELECT t.id_field from table t
JOIN . . .
JOIN . . .    
WHERE <10 rows of filtering criteria>

它在766毫秒内执行并带回411条记录

当我单独运行此查询时:

select t.id_field, t2.field1 from table t
LEFT JOIN table2 t2 ON t2.t_id_field = t.id_field
WHERE t.id_field in ( <I list out the varchar(8) values here from first query> )

它在3.031秒执行

但是,如果我尝试将查询放在一起,就像这样

select t.id_field, t2.field1 from table t
LEFT JOIN table2 t2 ON t2.t_id_field = t.id_field
WHERE t.id_field in ( 
    SELECT t.id_field from table t
    JOIN . . .
    JOIN . . .    
    WHERE <10 rows of filtering criteria>
 )

需要19.406秒

我尝试过如下的WITH语句:

WITH vt AS (
    SELECT t.id_field from table t
    JOIN . . .
    JOIN . . .    
    WHERE <10 rows of filtering criteria>
)
select vt.id_field, t2.field1 from vt
LEFT JOIN table2 t2 ON t2.t_id_field = vt.id_field

它在12秒内执行

我试过这个:

select t.id_field, t2.field1 from ( 
        SELECT tsub.id_field from table tsub
        JOIN . . .
        JOIN . . .    
        WHERE <10 rows of filtering criteria>
     ) t
LEFT JOIN table2 t2 ON t2.t_id_field = t.id_field

在12.750秒内执行

另一种尝试就是:

SELECT t.id_field, t2.field1 from table t
JOIN . . .
JOIN . . .
LEFT JOIN table2 t2 ON t2.t_id_field = t.id_field  
WHERE <10 rows of filtering criteria>

执行于12.813秒

关于如何让它达到至少3秒的任何想法,就像上面那个我手动输入值的那个?

这是执行计划

QUERY PLAN
Nested Loop Left Join  (cost=109243.37..119017.89 rows=1 width=83)
  CTE vc
    ->  Nested Loop  (cost=14871.86..109243.37 rows=1 width=7)
          ->  Nested Loop  (cost=14871.86..109242.01 rows=4 width=24)
                Join Filter: ((vsub.visit_disch_date <= da.da152_chgdt) AND (vsub.visit_arid = da.da152_arid))
                ->  Index Scan using da152_pkey on da152 da  (cost=0.00..10.40 rows=4 width=9)
                ->  Materialize  (cost=14871.86..109230.80 rows=12 width=19)
                      ->  Hash Right Join  (cost=14871.86..109230.74 rows=12 width=19)
                            Hash Cond: (((i.is1_num)::text = (vsub.visit_id)::text) AND ((i.is1_ins_full)::text = (vsub.visit_ins)::text))
                            Filter: (NULLIF(i.is1_bill_dt, '0001-01-01'::date) IS NULL)
                            ->  Seq Scan on insurance1 i  (cost=0.00..90993.64 rows=336264 width=14)
                            ->  Hash  (cost=14837.16..14837.16 rows=2313 width=19)
                                  ->  Seq Scan on visit vsub  (cost=0.00..14837.16 rows=2313 width=19)
                                        Filter: ((NULLIF(visit_disch_date, '0001-01-01'::date) IS NOT NULL) AND ((visit_servicecd_key)::text !~ '^[0-9]+$|[FHJbKkN\\+]'::text) AND ("left"((visit_id)::text, 1) <> ALL ('{F,P,J}'::text[])) AND (visit_mr_fdt >= (now() - '50 days'::interval)) AND (visit_mr_fdt <= (now() + '10 days'::interval)))
          ->  Index Scan using inscomp1_pkey on insurance_company_table1 inscomp1  (cost=0.00..0.33 rows=1 width=11)
                Index Cond: ((inscomp1_arid = vsub.visit_arid) AND ((inscomp1_comp)::text = (vsub.visit_ins)::text))
                Filter: (now() >= (vsub.visit_disch_date + ((inscomp1_lagdays)::double precision * '1 day'::interval)))
  ->  CTE Scan on vc  (cost=0.00..0.02 rows=1 width=12)
  ->  Index Scan using vdiag_pkey on visit_diagnosis vd  (cost=0.00..9774.48 rows=1 width=71)
        Index Cond: ((vdiag_visit_key)::text = (vc.visit_id)::text)
        Filter: ((vdiag_type)::text = 'A'::text)

和解释(分析,详细)(以“与上面的”查询示例“)

QUERY PLAN
Nested Loop Left Join  (cost=109243.36..119017.87 rows=1 width=83) (actual time=418.062..13796.260 rows=414 loops=1)
  Output: vc.visit_id, vd.vdiag_visit_key, vd.vdiag_arxseq, vd.vdiag_element, vd.vdiag_type, vd.vdiag_date, vd.vdiag_diag, vd.vdiag_arid
  CTE vc
    ->  Nested Loop  (cost=14871.84..109243.36 rows=1 width=7) (actual time=404.477..1006.518 rows=414 loops=1)
          Output: vsub.visit_id
          ->  Nested Loop  (cost=14871.84..109242.00 rows=4 width=24) (actual time=404.432..990.137 rows=418 loops=1)
                Output: vsub.visit_id, vsub.visit_ins, vsub.visit_arid, vsub.visit_disch_date, da.da152_arid
                Join Filter: ((vsub.visit_disch_date <= da.da152_chgdt) AND (vsub.visit_arid = da.da152_arid))
                Rows Removed by Join Filter: 1374
                ->  Index Scan using da152_pkey on public.da152 da  (cost=0.00..10.40 rows=4 width=9) (actual time=0.004..0.017 rows=4 loops=1)
                      Output: da.da152_rel_file_key_num, da.da152_contrl, da.da152_rcdt, da.da152_chgdt, da.da152_ar_rev, da.da152_ar_rc, da.da152_ar_rcar, da.da152_unpost, da.da152_lrun, da.da152_ar_month, da.da152_insdt, da.da152_otc_rcdt, da.da152_sum_rev, da.da152_sum_rc, da.da152_sum_rcar, da.da152_begbal, da.da152_netar, da.da152_arend, da.da152_eomtrial, da.da152_rc_da, da.da152_rc_amt_otc, da.da152_rc_amt_cp, da.da152_chg_thru, da.da152_ar_ldom, da.da152_csnum, da.da152_sec_e_bill, da.da152_uform, da.da152_jform, da.da152_rate, da.da152_contract_bill, da.da152_up_front, da.da152_bad_debt, da.da152_pat_refund, da.da152_2cnd_ins, da.da152_pat_type1, da.da152_pat_type2, da.da152_pat_srvcd1_old, da.da152_pat_srvcd2_old, da.da152_wo_colcd1, da.da152_wo_alpha1s, da.da152_wo_alpha1e, da.da152_wo_colcd2, da.da152_wo_alpha2s, da.da152_wo_alpha2e, da.da152_wo_colcd3, da.da152_wo_alpha3s, da.da152_wo_alpha3e, da.da152_ins_prim, da.da152_tic_xfc1, da.da152_tic_xfc2, da.da152_ins_fc, da.da152_wo_sitnum, da.da152_wo_sit_cd, da.da152_ins2dt, da.da152_multicoqual, da.da152_multicoid, da.da152_multicodir, da.da152_multicoglnum, da.da152_pat_srvcd1, da.da152_pat_srvcd2, da.da152_adchg, da.da152_adchg_var, da.da152_month_closedt, da.da152_pat_colcd, da.da152_nonaracct, da.da152_isfup_days, da.da152_arid
                ->  Materialize  (cost=14871.84..109230.79 rows=12 width=19) (actual time=101.103..246.563 rows=448 loops=4)
                      Output: vsub.visit_id, vsub.visit_ins, vsub.visit_arid, vsub.visit_disch_date
                      ->  Hash Right Join  (cost=14871.84..109230.73 rows=12 width=19) (actual time=404.408..983.328 rows=448 loops=1)
                            Output: vsub.visit_id, vsub.visit_ins, vsub.visit_arid, vsub.visit_disch_date
                            Hash Cond: (((i.is1_num)::text = (vsub.visit_id)::text) AND ((i.is1_ins_full)::text = (vsub.visit_ins)::text))
                            Filter: (NULLIF(i.is1_bill_dt, '0001-01-01'::date) IS NULL)
                            Rows Removed by Filter: 2018
                            ->  Seq Scan on public.insurance1 i  (cost=0.00..90993.64 rows=336264 width=14) (actual time=0.002..284.366 rows=341073 loops=1)
                                  Output: i.is1_num, i.is1_ins_full, i.is1_set, i.is1_prim, i.is1_stay, i.is1_direct, i.is1_admit, i.is1_disc, i.is1_from, i.is1_to, i.is1_app_sent, i.is1_app_rec, i.is1_gen_dt, i.is1_ck_dt, i.is1_contract_old, i.is1_bill_dt, i.is1_pd_dt1, i.is1_pd_amt1, i.is1_pd_dt2, i.is1_pd_amt2, i.is1_pd_dt3, i.is1_pd_amt3, i.is1_pd_status, i.is1_med_ness, i.is1_bl_furn, i.is1_bl_rep, i.is1_bl_n_rep, i.is1_bl_rate, i.is1_bl_chg, i.is1_bl_non, i.is1_coamt, i.is1_expay, i.is1_semi_rate, i.is1_diem, i.is1_cd, i.is1_typrm, i.is1_qty, i.is1_chg, i.is1_non, i.is1_opcd, i.is1_opdate, i.is1_opdesc, i.is1_opchg, i.is1_opphy, i.is1_totchg, i.is1_totnon, i.is1_maxlines, i.is1_totlines, i.is1_apc_sw, i.is1_eapc_reim, i.is1_eapc_copay, i.is1_eapc_contr, i.is1_eapc_ded, i.is1_eapc_outlr, i.is1_aapc_reim, i.is1_aapc_copay, i.is1_aapc_contr, i.is1_aapc_ded, i.is1_aapc_outlr, i.is1_mr_okayed, i.is1_mr_ok_init, i.is1_a_ded, i.is1_dayfull, i.is1_dayco, i.is1_daylife, i.is1_bl_ded, i.is1_bl_d_amt, i.is1_contr2, i.is1_copay, i.is1_colim, i.is1_covrmrate, i.is1_lifeused, i.is1_covdays, i.is1_nondays, i.is1_co_used, i.is1_typary, i.is1_effdt, i.is1_covrate, i.is1_endcare, i.is1_drg, i.is1_p_name, i.is1_birth, i.is1_print, i.is1_mndays, i.is1_reim_amt, i.is1_elecbill, i.is1_elecdate, i.is1_ppscode, i.is1_psrocode, i.is1_typebill, i.is1_new_op_medicare, i.is1_netreim, i.is1_serv, i.is1_printcross, i.is1_crossdate, i.is1_filetype, i.is1_releaseinfo, i.is1_pdtype1, i.is1_pdtype2, i.is1_pdtype3, i.is1_coins, i.is1_otprim, i.is1_otins, i.is1_otset, i.is1_coveragesetby, i.is1_covcalctype, i.is1_covverified, i.is1_netcalc, i.is1_orig_expay, i.is1_orig_bl_d_amt, i.is1_orig_coamt, i.is1_orig_a_ded, i.is1_orig_drg, i.is1_orig_covdays, i.is1_excrep, i.is1_exccov, i.is1_genviaautocl, i.is1_autobill, i.is1_formver, i.is1_contract, i.is1_origin, i.is1_covgoverride, i.is1_covglogname, i.is1_covgcsnum, i.is1_excchgs, i.is1_arid, i.is1_drg_icd10
                            ->  Hash  (cost=14837.16..14837.16 rows=2312 width=19) (actual time=394.738..394.738 rows=2416 loops=1)
                                  Output: vsub.visit_id, vsub.visit_ins, vsub.visit_arid, vsub.visit_disch_date
                                  Buckets: 1024  Batches: 1  Memory Usage: 123kB
                                  ->  Seq Scan on public.visit vsub  (cost=0.00..14837.16 rows=2312 width=19) (actual time=0.097..391.839 rows=2416 loops=1)
                                        Output: vsub.visit_id, vsub.visit_ins, vsub.visit_arid, vsub.visit_disch_date
                                        Filter: ((NULLIF(vsub.visit_disch_date, '0001-01-01'::date) IS NOT NULL) AND ((vsub.visit_servicecd_key)::text !~ '^[0-9]+$|[FHJbKkN\\+]'::text) AND ("left"((vsub.visit_id)::text, 1) <> ALL ('{F,P,J}'::text[])) AND (vsub.visit_mr_fdt >= (now() - '50 days'::interval)) AND (vsub.visit_mr_fdt <= (now() + '10 days'::interval)))
                                        Rows Removed by Filter: 201579
          ->  Index Scan using inscomp1_pkey on public.insurance_company_table1 inscomp1  (cost=0.00..0.33 rows=1 width=11) (actual time=0.029..0.031 rows=1 loops=418)
                Output: inscomp1.inscomp1_comp, inscomp1.inscomp1_name, inscomp1.inscomp1_addr1, inscomp1.inscomp1_addr2, inscomp1.inscomp1_city, inscomp1.inscomp1_state, inscomp1.inscomp1_zip, inscomp1.inscomp1_form, inscomp1.inscomp1_jour, inscomp1.inscomp1_prov, inscomp1.inscomp1_typebill, inscomp1.inscomp1_perdiem, inscomp1.inscomp1_diemdt, inscomp1.inscomp1_priordiem, inscomp1.inscomp1_pcused, inscomp1.inscomp1_phybillsw, inscomp1.inscomp1_approval, inscomp1.inscomp1_psro, inscomp1.inscomp1_ask_reim, inscomp1.inscomp1_reject_days, inscomp1.inscomp1_contrgl, inscomp1.inscomp1_othargl, inscomp1.inscomp1_auto_ip, inscomp1.inscomp1_auto_op, inscomp1.inscomp1_prirate, inscomp1.inscomp1_secrate, inscomp1.inscomp1_lagdays, inscomp1.inscomp1_mul1500, inscomp1.inscomp1_waitfin, inscomp1.inscomp1_opsum, inscomp1.inscomp1_write_off, inscomp1.inscomp1_transmit, inscomp1.inscomp1_detail_bl, inscomp1.inscomp1_provname, inscomp1.inscomp1_provaddr1, inscomp1.inscomp1_provaddr2, inscomp1.inscomp1_provcity, inscomp1.inscomp1_provst, inscomp1.inscomp1_provzip, inscomp1.inscomp1_cont_perc, inscomp1.inscomp1_drg_str, inscomp1.inscomp1_drg_acps, inscomp1.inscomp1_drg_dt, inscomp1.inscomp1_ub_loc2, inscomp1.inscomp1_sub_id, inscomp1.inscomp1_bcno, inscomp1.inscomp1_taxno, inscomp1.inscomp1_mcareno, inscomp1.inscomp1_mcaidno, inscomp1.inscomp1_signature, inscomp1.inscomp1_prov2, inscomp1.inscomp1_allpay, inscomp1.inscomp1_discrate, inscomp1.inscomp1_discdt, inscomp1.inscomp1_discrate2, inscomp1.inscomp1_sumitem, inscomp1.inscomp1_bank_plan, inscomp1.inscomp1_phy_1500, inscomp1.inscomp1_labmc, inscomp1.inscomp1_orer_comb, inscomp1.inscomp1_phybillex, inscomp1.inscomp1_net_reim, inscomp1.inscomp1_ask_drg, inscomp1.inscomp1_provphone, inscomp1.inscomp1_drggroup, inscomp1.inscomp1_phyins, inscomp1.inscomp1_phyub82, inscomp1.inscomp1_mnxsnf, inscomp1.inscomp1_srcpmtcde, inscomp1.inscomp1_provname2, inscomp1.inscomp1_coll_id, inscomp1.inscomp1_diagptr, inscomp1.inscomp1_tax, inscomp1.inscomp1_type_desc, inscomp1.inscomp1_revcode, inscomp1.inscomp1_arid
                Index Cond: ((inscomp1.inscomp1_arid = vsub.visit_arid) AND ((inscomp1.inscomp1_comp)::text = (vsub.visit_ins)::text))
                Filter: (now() >= (vsub.visit_disch_date + ((inscomp1.inscomp1_lagdays)::double precision * '1 day'::interval)))
  ->  CTE Scan on vc  (cost=0.00..0.02 rows=1 width=12) (actual time=404.481..1008.180 rows=414 loops=1)
        Output: vc.visit_id
  ->  Index Scan using vdiag_pkey on public.visit_diagnosis vd  (cost=0.00..9774.48 rows=1 width=71) (actual time=14.246..30.882 rows=1 loops=414)
        Output: vd.vdiag_visit_key, vd.vdiag_arxseq, vd.vdiag_element, vd.vdiag_type, vd.vdiag_date, vd.vdiag_diag, vd.vdiag_arid
        Index Cond: ((vd.vdiag_visit_key)::text = (vc.visit_id)::text)
        Filter: ((vd.vdiag_type)::text = 'A'::text)
        Rows Removed by Filter: 1
Total runtime: 13796.881 ms

解释(分析,VERBOSE)只是为了获得要去的MILLISECONDS

QUERY PLAN
Nested Loop  (cost=14871.84..109244.42 rows=1 width=7) (actual time=403.659..985.167 rows=432 loops=1)
  Output: vsub.visit_id
  ->  Nested Loop  (cost=14871.84..109243.06 rows=4 width=24) (actual time=403.618..980.483 rows=441 loops=1)
        Output: vsub.visit_id, vsub.visit_ins, vsub.visit_arid, vsub.visit_disch_date, da.da152_arid
        Join Filter: ((vsub.visit_disch_date <= da.da152_chgdt) AND (vsub.visit_arid = da.da152_arid))
        Rows Removed by Join Filter: 1351
        ->  Index Scan using da152_pkey on public.da152 da  (cost=0.00..10.40 rows=4 width=9) (actual time=0.004..0.014 rows=4 loops=1)
              Output: da.da152_rel_file_key_num, da.da152_contrl, da.da152_rcdt, da.da152_chgdt, da.da152_ar_rev, da.da152_ar_rc, da.da152_ar_rcar, da.da152_unpost, da.da152_lrun, da.da152_ar_month, da.da152_insdt, da.da152_otc_rcdt, da.da152_sum_rev, da.da152_sum_rc, da.da152_sum_rcar, da.da152_begbal, da.da152_netar, da.da152_arend, da.da152_eomtrial, da.da152_rc_da, da.da152_rc_amt_otc, da.da152_rc_amt_cp, da.da152_chg_thru, da.da152_ar_ldom, da.da152_csnum, da.da152_sec_e_bill, da.da152_uform, da.da152_jform, da.da152_rate, da.da152_contract_bill, da.da152_up_front, da.da152_bad_debt, da.da152_pat_refund, da.da152_2cnd_ins, da.da152_pat_type1, da.da152_pat_type2, da.da152_pat_srvcd1_old, da.da152_pat_srvcd2_old, da.da152_wo_colcd1, da.da152_wo_alpha1s, da.da152_wo_alpha1e, da.da152_wo_colcd2, da.da152_wo_alpha2s, da.da152_wo_alpha2e, da.da152_wo_colcd3, da.da152_wo_alpha3s, da.da152_wo_alpha3e, da.da152_ins_prim, da.da152_tic_xfc1, da.da152_tic_xfc2, da.da152_ins_fc, da.da152_wo_sitnum, da.da152_wo_sit_cd, da.da152_ins2dt, da.da152_multicoqual, da.da152_multicoid, da.da152_multicodir, da.da152_multicoglnum, da.da152_pat_srvcd1, da.da152_pat_srvcd2, da.da152_adchg, da.da152_adchg_var, da.da152_month_closedt, da.da152_pat_colcd, da.da152_nonaracct, da.da152_isfup_days, da.da152_arid
        ->  Materialize  (cost=14871.84..109231.85 rows=12 width=19) (actual time=100.901..244.629 rows=448 loops=4)
              Output: vsub.visit_id, vsub.visit_ins, vsub.visit_arid, vsub.visit_disch_date
              ->  Hash Right Join  (cost=14871.84..109231.79 rows=12 width=19) (actual time=403.596..976.869 rows=448 loops=1)
                    Output: vsub.visit_id, vsub.visit_ins, vsub.visit_arid, vsub.visit_disch_date
                    Hash Cond: (((i.is1_num)::text = (vsub.visit_id)::text) AND ((i.is1_ins_full)::text = (vsub.visit_ins)::text))
                    Filter: (NULLIF(i.is1_bill_dt, '0001-01-01'::date) IS NULL)
                    Rows Removed by Filter: 2018
                    ->  Seq Scan on public.insurance1 i  (cost=0.00..90994.67 rows=336267 width=14) (actual time=0.002..283.076 rows=341075 loops=1)
                          Output: i.is1_num, i.is1_ins_full, i.is1_set, i.is1_prim, i.is1_stay, i.is1_direct, i.is1_admit, i.is1_disc, i.is1_from, i.is1_to, i.is1_app_sent, i.is1_app_rec, i.is1_gen_dt, i.is1_ck_dt, i.is1_contract_old, i.is1_bill_dt, i.is1_pd_dt1, i.is1_pd_amt1, i.is1_pd_dt2, i.is1_pd_amt2, i.is1_pd_dt3, i.is1_pd_amt3, i.is1_pd_status, i.is1_med_ness, i.is1_bl_furn, i.is1_bl_rep, i.is1_bl_n_rep, i.is1_bl_rate, i.is1_bl_chg, i.is1_bl_non, i.is1_coamt, i.is1_expay, i.is1_semi_rate, i.is1_diem, i.is1_cd, i.is1_typrm, i.is1_qty, i.is1_chg, i.is1_non, i.is1_opcd, i.is1_opdate, i.is1_opdesc, i.is1_opchg, i.is1_opphy, i.is1_totchg, i.is1_totnon, i.is1_maxlines, i.is1_totlines, i.is1_apc_sw, i.is1_eapc_reim, i.is1_eapc_copay, i.is1_eapc_contr, i.is1_eapc_ded, i.is1_eapc_outlr, i.is1_aapc_reim, i.is1_aapc_copay, i.is1_aapc_contr, i.is1_aapc_ded, i.is1_aapc_outlr, i.is1_mr_okayed, i.is1_mr_ok_init, i.is1_a_ded, i.is1_dayfull, i.is1_dayco, i.is1_daylife, i.is1_bl_ded, i.is1_bl_d_amt, i.is1_contr2, i.is1_copay, i.is1_colim, i.is1_covrmrate, i.is1_lifeused, i.is1_covdays, i.is1_nondays, i.is1_co_used, i.is1_typary, i.is1_effdt, i.is1_covrate, i.is1_endcare, i.is1_drg, i.is1_p_name, i.is1_birth, i.is1_print, i.is1_mndays, i.is1_reim_amt, i.is1_elecbill, i.is1_elecdate, i.is1_ppscode, i.is1_psrocode, i.is1_typebill, i.is1_new_op_medicare, i.is1_netreim, i.is1_serv, i.is1_printcross, i.is1_crossdate, i.is1_filetype, i.is1_releaseinfo, i.is1_pdtype1, i.is1_pdtype2, i.is1_pdtype3, i.is1_coins, i.is1_otprim, i.is1_otins, i.is1_otset, i.is1_coveragesetby, i.is1_covcalctype, i.is1_covverified, i.is1_netcalc, i.is1_orig_expay, i.is1_orig_bl_d_amt, i.is1_orig_coamt, i.is1_orig_a_ded, i.is1_orig_drg, i.is1_orig_covdays, i.is1_excrep, i.is1_exccov, i.is1_genviaautocl, i.is1_autobill, i.is1_formver, i.is1_contract, i.is1_origin, i.is1_covgoverride, i.is1_covglogname, i.is1_covgcsnum, i.is1_excchgs, i.is1_arid, i.is1_drg_icd10
                    ->  Hash  (cost=14837.16..14837.16 rows=2312 width=19) (actual time=393.928..393.928 rows=2416 loops=1)
                          Output: vsub.visit_id, vsub.visit_ins, vsub.visit_arid, vsub.visit_disch_date
                          Buckets: 1024  Batches: 1  Memory Usage: 123kB
                          ->  Seq Scan on public.visit vsub  (cost=0.00..14837.16 rows=2312 width=19) (actual time=0.088..391.163 rows=2416 loops=1)
                                Output: vsub.visit_id, vsub.visit_ins, vsub.visit_arid, vsub.visit_disch_date
                                Filter: ((NULLIF(vsub.visit_disch_date, '0001-01-01'::date) IS NOT NULL) AND ((vsub.visit_servicecd_key)::text !~ '^[0-9]+$|[FHJbKkN\\+]'::text) AND ("left"((vsub.visit_id)::text, 1) <> ALL ('{F,P,J}'::text[])) AND (vsub.visit_mr_fdt >= (now() - '50 days'::interval)) AND (vsub.visit_mr_fdt <= (now() + '10 days'::interval)))
                                Rows Removed by Filter: 201581
  ->  Index Scan using inscomp1_pkey on public.insurance_company_table1 inscomp1  (cost=0.00..0.33 rows=1 width=11) (actual time=0.007..0.008 rows=1 loops=441)
        Output: inscomp1.inscomp1_comp, inscomp1.inscomp1_name, inscomp1.inscomp1_addr1, inscomp1.inscomp1_addr2, inscomp1.inscomp1_city, inscomp1.inscomp1_state, inscomp1.inscomp1_zip, inscomp1.inscomp1_form, inscomp1.inscomp1_jour, inscomp1.inscomp1_prov, inscomp1.inscomp1_typebill, inscomp1.inscomp1_perdiem, inscomp1.inscomp1_diemdt, inscomp1.inscomp1_priordiem, inscomp1.inscomp1_pcused, inscomp1.inscomp1_phybillsw, inscomp1.inscomp1_approval, inscomp1.inscomp1_psro, inscomp1.inscomp1_ask_reim, inscomp1.inscomp1_reject_days, inscomp1.inscomp1_contrgl, inscomp1.inscomp1_othargl, inscomp1.inscomp1_auto_ip, inscomp1.inscomp1_auto_op, inscomp1.inscomp1_prirate, inscomp1.inscomp1_secrate, inscomp1.inscomp1_lagdays, inscomp1.inscomp1_mul1500, inscomp1.inscomp1_waitfin, inscomp1.inscomp1_opsum, inscomp1.inscomp1_write_off, inscomp1.inscomp1_transmit, inscomp1.inscomp1_detail_bl, inscomp1.inscomp1_provname, inscomp1.inscomp1_provaddr1, inscomp1.inscomp1_provaddr2, inscomp1.inscomp1_provcity, inscomp1.inscomp1_provst, inscomp1.inscomp1_provzip, inscomp1.inscomp1_cont_perc, inscomp1.inscomp1_drg_str, inscomp1.inscomp1_drg_acps, inscomp1.inscomp1_drg_dt, inscomp1.inscomp1_ub_loc2, inscomp1.inscomp1_sub_id, inscomp1.inscomp1_bcno, inscomp1.inscomp1_taxno, inscomp1.inscomp1_mcareno, inscomp1.inscomp1_mcaidno, inscomp1.inscomp1_signature, inscomp1.inscomp1_prov2, inscomp1.inscomp1_allpay, inscomp1.inscomp1_discrate, inscomp1.inscomp1_discdt, inscomp1.inscomp1_discrate2, inscomp1.inscomp1_sumitem, inscomp1.inscomp1_bank_plan, inscomp1.inscomp1_phy_1500, inscomp1.inscomp1_labmc, inscomp1.inscomp1_orer_comb, inscomp1.inscomp1_phybillex, inscomp1.inscomp1_net_reim, inscomp1.inscomp1_ask_drg, inscomp1.inscomp1_provphone, inscomp1.inscomp1_drggroup, inscomp1.inscomp1_phyins, inscomp1.inscomp1_phyub82, inscomp1.inscomp1_mnxsnf, inscomp1.inscomp1_srcpmtcde, inscomp1.inscomp1_provname2, inscomp1.inscomp1_coll_id, inscomp1.inscomp1_diagptr, inscomp1.inscomp1_tax, inscomp1.inscomp1_type_desc, inscomp1.inscomp1_revcode, inscomp1.inscomp1_arid
        Index Cond: ((inscomp1.inscomp1_arid = vsub.visit_arid) AND ((inscomp1.inscomp1_comp)::text = (vsub.visit_ins)::text))
        Filter: (now() >= (vsub.visit_disch_date + ((inscomp1.inscomp1_lagdays)::double precision * '1 day'::interval)))
        Rows Removed by Filter: 0
Total runtime: 985.603 ms

2 个答案:

答案 0 :(得分:1)

完全重写您的查询:

  • 仅保留外部查询中的访问和诊断表
  • 将其余表格(仅用作条件)移动到EXISTS()短语
  • NULLIF(a,b) IS NULL重写为a > b,因为b似乎是一个N / A标记值(我建议-infinity为此,或者只是NULL)
  • 并将一个LEFT JOIN ... NULL更改为NOT EXISTS(...)构造。
  • 未经测试的,因为我没有表格定义
WITH vCriteria AS (
    SELECT vs.visit_id, vd.vdiag_diag  
    FROM visit vs
    LEFT JOIN visit_diagnosis vd ON vd.vdiag_visit_key = vs.visit_id
    WHERE EXISTS ( SELECT *  
        FROM da152 da 
        WHERE da.da152_arid = vs.visit_arid 
        AND vs.visit_disch_date <= da.da152_chgdt
        )
    AND EXISTS ( SELECT *
        FROM insurance_company_table1 ict  
        WHERE ict.inscomp1_comp = vs.visit_ins
        AND ict.inscomp1_arid = vs.visit_arid
        AND Now() >= (vs.visit_disch_date + ict.inscomp1_lagdays * INTERVAL '1 day')
        )
    AND NOT EXISTS (
        SELECT * 
        FROM insurance1 ins 
        WHERE ins.is1_num = vs.visit_id AND ins.is1_ins_full = vs.visit_ins
        AND ins.is1_bill_dt > '0001-01-01'::date
        )
    AND vs.visit_mr_fdt
      BETWEEN (now() - 50 * INTERVAL '1 day') AND (now() + 10 * INTERVAL '1 day')
    AND vs.visit_disch_date > '0001-01-01'::date
    AND vs.visit_servicecd_key ~ '^[0-9]+$|[FHJbKkN\\+]' = false
    AND LEFT (vs.visit_id, 1) NOT IN ('F', 'P', 'J') 
) 
SELECT vCriteria.* FROM vCriteria
        ;

答案 1 :(得分:0)

这不会回答为什么,但我希望它有助于提供一些见解。我发现了一个列表:

select a from t1 where x in (select y from t2)
当列表中的基数较低时,

就可以了,但随着列表大小的增加,效率会降低。相比之下,sem-join:

select a
from t1
where exists (
  select null
  from t2.x = t2.y
  where t1.
)
对于大或小的列表,

几乎总是有效的。

出于懒惰,我已经在我的第一次黑客中使用了列表并几乎一直后悔。当我切换到半连接时,世界应该是应有的。

那么,您是否可以尝试将查询更改为此内容并查看会发生什么?

select t.id_field, t2.field1 from table t
LEFT JOIN table2 t2 ON t2.t_id_field = t.id_field
WHERE exists (
  select 1
  from table tt
  join . . .
  join . . .
  where
    t.id_field = tt.id_field and
     <10 rows of filtering criteria>
 )

要明确的是,半连接和连接之间的区别在于,如果列表中包含重复,则半连接会忽略后续出现。它不仅不会使行结果倍增,而且会为每场比赛“停止查看”。

但至于你的主要问题 - 你可以把它降到原来的三秒钟吗?我对此表示怀疑,因为我怀疑内部查询是额外的九秒来自哪里。

- 编辑 -

这可能比你愿意处理的代码更多,以节省9秒,但是当你运行它时会发生什么?

CREATE OR REPLACE FUNCTION test()
  RETURNS TABLE (
    id_field varchar,
    field1   varchar
  ) AS
$BODY$
  DECLARE
    id_field_list varchar[];
  BEGIN
    SELECT array_agg (t.id_field)
    into id_field_list
    from table t
    JOIN . . .
    JOIN . . .    
    WHERE <10 rows of filtering criteria>;

    return query
    select t.id_field, t2.field1 from table t
    LEFT JOIN table2 t2 ON t2.t_id_field = t.id_field
    WHERE t.id_field = any(id_field_list);
  END
$BODY$
LANGUAGE plpgsql;

当然,您可以从以下网址获取查询结果:

select * from test();