未首先执行 Postgres WITH

Nat*_*ner 5 postgresql cte postgresql-9.5

我正在 PostgreSQL 9.5 中处理从两个视图中提取的 SQL 查询。单独来看,这些视图需要 93 毫秒和 530 毫秒来执行,分别产生 ~1500 和 ~6200 行。鉴于处理进入视图,这似乎是合理的,其中包括与 PostGIS 的一些空间交叉点。但是,当我执行下面的查询时,大约需要 5 秒才能执行。

据我所知, usingWITH应该强制子查询在下面的查询中的评估之前执行一次,这应该导致总时间不到一秒而不是五秒。

如果我通过 ODBC/MS Access 链接到两个视图并使用 MS Access 在没有 的情况下执行查询WITH,它会在不到一秒的时间内执行。这让我认为,当我在 pgAdmin 中执行子查询时,在加入之前不会每次都执行一次。

视图中没有其他 CTE,只有子查询。

有没有更好的方法来做到这一点,或者强制执行顺序的黑客?

WITH 
  eu AS (
    SELECT
      e.sample_pk,
      .....
    FROM
      public.samples_exp_unit AS e
    ),
  sr AS (
    SELECT
      r.sample_pk,
      .....
    FROM
      public.sample_results AS r
    )

SELECT
  sr.sample_pk,
  eu.inventory_pk,
  .....
FROM sr INNER JOIN eu
ON sr.sample_pk = eu.sample_pk
Run Code Online (Sandbox Code Playgroud)

全查询的执行计划:

"Hash Join  (cost=963.49..1007.02 rows=9 width=120) (actual time=40.508..54.209 rows=45392 loops=1)"
"  Hash Cond: (sr.sample_pk = eu.sample_pk)"
"  CTE eu"
"    ->  Nested Loop  (cost=41.81..50.67 rows=1 width=24) (actual time=1.296..8.307 rows=1538 loops=1)"
"          Join Filter: (lil.locations_pk = l.locations_pk)"
"          ->  Nested Loop  (cost=41.67..48.22 rows=1 width=28) (actual time=1.289..6.582 rows=1538 loops=1)"
"                ->  Nested Loop  (cost=41.53..47.92 rows=1 width=32) (actual time=1.283..4.852 rows=1538 loops=1)"
"                      ->  Hash Join  (cost=41.38..47.66 rows=1 width=28) (actual time=1.275..3.079 rows=1480 loops=1)"
"                            Hash Cond: (lil.locations_pk = eu_1.locations_pk)"
"                            Join Filter: ((((sd.sample_depth_bottom)::double precision - eu_1.poc_top) > '-0.0001'::double precision) AND ((eu_1.poc_bottom - (sd.sample_depth_top)::double precision) > '-0.0001'::double precision))"
"                            Rows Removed by Join Filter: 371"
"                            ->  Hash Join  (cost=40.23..46.36 rows=5 width=29) (actual time=1.252..1.402 rows=610 loops=1)"
"                                  Hash Cond: (sd.inventory_pk = i.inventory_pk)"
"                                  ->  Seq Scan on sample_description sd  (cost=0.00..5.25 rows=225 width=17) (actual time=0.004..0.049 rows=225 loops=1)"
"                                  ->  Hash  (cost=40.19..40.19 rows=3 width=16) (actual time=1.245..1.245 rows=418 loops=1)"
"                                        Buckets: 1024  Batches: 1  Memory Usage: 28kB"
"                                        ->  Hash Join  (cost=35.92..40.19 rows=3 width=16) (actual time=1.109..1.194 rows=418 loops=1)"
"                                              Hash Cond: (i.inv_loc_pk = lil.inv_loc_pk)"
"                                              ->  Seq Scan on inv i  (cost=0.00..3.63 rows=163 width=8) (actual time=0.004..0.025 rows=163 loops=1)"
"                                              ->  Hash  (cost=35.88..35.88 rows=3 width=8) (actual time=1.102..1.102 rows=390 loops=1)"
"                                                    Buckets: 1024  Batches: 1  Memory Usage: 24kB"
"                                                    ->  Subquery Scan on lil  (cost=35.82..35.88 rows=3 width=8) (actual time=1.002..1.056 rows=390 loops=1)"
"                                                          ->  HashAggregate  (cost=35.82..35.85 rows=3 width=8) (actual time=1.001..1.037 rows=390 loops=1)"
"                                                                Group Key: "*SELECT* 1".locations_pk, "*SELECT* 1".inv_loc_pk"
"                                                                ->  Append  (cost=0.14..35.81 rows=3 width=8) (actual time=0.876..0.929 rows=390 loops=1)"
"                                                                      ->  Result  (cost=0.14..34.78 rows=2 width=8) (actual time=0.876..0.918 rows=389 loops=1)"
"                                                                            ->  HashSetOp Except  (cost=0.14..34.78 rows=2 width=8) (actual time=0.876..0.892 rows=389 loops=1)"
"                                                                                  ->  Append  (cost=0.14..34.77 rows=3 width=8) (actual time=0.028..0.800 rows=389 loops=1)"
"                                                                                        ->  Subquery Scan on "*SELECT* 1"  (cost=0.14..33.75 rows=2 width=8) (actual time=0.028..0.785 rows=389 loops=1)"
"                                                                                              ->  Nested Loop  (cost=0.14..33.73 rows=2 width=8) (actual time=0.026..0.759 rows=389 loops=1)"
"                                                                                                    ->  Seq Scan on locations l_1  (cost=0.00..2.37 rows=37 width=36) (actual time=0.003..0.012 rows=38 loops=1)"
"                                                                                                    ->  Index Scan using sidx_inv_loc_geom on inv_loc i_1  (cost=0.14..0.84 rows=1 width=36) (actual time=0.008..0.018 rows=10 loops=38)"
"                                                                                                          Index Cond: (geom && l_1.geom)"
"                                                                                                          Filter: _st_intersects(geom, l_1.geom)"
"                                                                                                          Rows Removed by Filter: 0"
"                                                                                        ->  Subquery Scan on "*SELECT* 2"  (cost=0.00..1.02 rows=1 width=8) (actual time=0.003..0.003 rows=0 loops=1)"
"                                                                                              ->  Seq Scan on loc_inv_adjust a  (cost=0.00..1.01 rows=1 width=8) (actual time=0.003..0.003 rows=0 loops=1)"
"                                                                                                    Filter: (include = 0)"
"                                                                                                    Rows Removed by Filter: 1"
"                                                                      ->  Seq Scan on loc_inv_adjust b  (cost=0.00..1.01 rows=1 width=8) (actual time=0.002..0.002 rows=1 loops=1)"
"                                                                            Filter: (include = 1)"
"                            ->  Hash  (cost=1.07..1.07 rows=7 width=24) (actual time=0.009..0.009 rows=11 loops=1)"
"                                  Buckets: 1024  Batches: 1  Memory Usage: 9kB"
"                                  ->  Seq Scan on exp_unit eu_1  (cost=0.00..1.07 rows=7 width=24) (actual time=0.004..0.006 rows=11 loops=1)"
"                      ->  Index Scan using bysampledescription on sample s  (cost=0.14..0.25 rows=1 width=8) (actual time=0.001..0.001 rows=1 loops=1480)"
"                            Index Cond: (sample_description_pk = sd.sample_description_pk)"
"                ->  Index Only Scan using inv_loc_pkey on inv_loc il  (cost=0.14..0.29 rows=1 width=4) (actual time=0.001..0.001 rows=1 loops=1538)"
"                      Index Cond: (inv_loc_pk = i.inv_loc_pk)"
"                      Heap Fetches: 1538"
"          ->  Index Only Scan using pk_locations on locations l  (cost=0.14..2.44 rows=1 width=4) (actual time=0.001..0.001 rows=1 loops=1538)"
"                Index Cond: (locations_pk = eu_1.locations_pk)"
"                Heap Fetches: 1538"
"  CTE sr"
"    ->  WindowAgg  (cost=848.77..894.49 rows=1829 width=92) (actual time=31.316..35.704 rows=6234 loops=1)"
"          ->  Sort  (cost=848.77..853.34 rows=1829 width=92) (actual time=31.312..31.621 rows=6234 loops=1)"
"                Sort Key: sub_query_union.sample_pk, sub_query_union.analyte_pk, sub_query_union.type_priority, sub_query_union.num_priority"
"                Sort Method: quicksort  Memory: 1069kB"
"                ->  Subquery Scan on sub_query_union  (cost=713.08..749.66 rows=1829 width=92) (actual time=26.511..28.164 rows=6234 loops=1)"
"                      ->  HashAggregate  (cost=713.08..731.37 rows=1829 width=106) (actual time=26.510..27.750 rows=6234 loops=1)"
"                            Group Key: "*SELECT* 1_1".sample_pk, "*SELECT* 1_1".analyte_pk, "*SELECT* 1_1".results_pk, (1), "*SELECT* 1_1".result, "*SELECT* 1_1".units_pk, (NULL::double precision), (NULL::double precision), ('Rep_Conc'::character varying), (...)"
"                            ->  Append  (cost=46.85..658.21 rows=1829 width=106) (actual time=3.748..22.017 rows=6234 loops=1)"
"                                  ->  Subquery Scan on "*SELECT* 1_1"  (cost=46.85..62.83 rows=1 width=24) (actual time=3.748..5.539 rows=134 loops=1)"
"                                        ->  Nested Loop  (cost=46.85..62.82 rows=1 width=24) (actual time=3.746..5.485 rows=134 loops=1)"
"                                              Join Filter: (lil_1.locations_pk = l_2.locations_pk)"
"                                              ->  Nested Loop  (cost=46.71..62.60 rows=1 width=32) (actual time=3.736..4.981 rows=134 loops=1)"
"                                                    ->  Nested Loop  (cost=46.57..62.31 rows=1 width=40) (actual time=3.727..4.584 rows=134 loops=1)"
"                                                          ->  Hash Join  (cost=46.42..62.05 rows=1 width=40) (actual time=3.718..4.177 rows=128 loops=1)"
"                                                                Hash Cond: (rc.locations_pk = lil_1.locations_pk)"
"                                                                Join Filter: ((((sd_1.sample_depth_bottom)::double precision - rc.depth_top) > '-0.0001'::double precision) AND ((rc.depth_bottom - (sd_1.sample_depth_top)::double precision) > '-0.0001'::doub (...)"
"                                                                Rows Removed by Join Filter: 94"
"                                                                ->  Seq Scan on rep_conc rc  (cost=0.00..13.60 rows=360 width=40) (actual time=0.005..0.006 rows=1 loops=1)"
"                                                                ->  Hash  (cost=46.36..46.36 rows=5 width=25) (actual time=3.683..3.683 rows=610 loops=1)"
"                                                                      Buckets: 1024  Batches: 1  Memory Usage: 43kB"
"                                                                      ->  Hash Join  (cost=40.23..46.36 rows=5 width=25) (actual time=3.124..3.444 rows=610 loops=1)"
"                                                                            Hash Cond: (sd_1.inventory_pk = i_2.inventory_pk)"
"                                                                            ->  Seq Scan on sample_description sd_1  (cost=0.00..5.25 rows=225 width=17) (actual time=0.006..0.093 rows=225 loops=1)"
"                                                                            ->  Hash  (cost=40.19..40.19 rows=3 width=16) (actual time=3.111..3.111 rows=418 loops=1)"
"                                                                                  Buckets: 1024  Batches: 1  Memory Usage: 28kB"
"                                                                                  ->  Hash Join  (cost=35.92..40.19 rows=3 width=16) (actual time=2.780..2.976 rows=418 loops=1)"
"                                                                                        Hash Cond: (i_2.inv_loc_pk = lil_1.inv_loc_pk)"
"                                                                                        ->  Seq Scan on inv i_2  (cost=0.00..3.63 rows=163 width=8) (actual time=0.007..0.059 rows=163 loops=1)"
"                                                                                        ->  Hash  (cost=35.88..35.88 rows=3 width=8) (actual time=2.761..2.761 rows=390 loops=1)"
"                                                                                              Buckets: 1024  Batches: 1  Memory Usage: 24kB"
"                                                                                              ->  Subquery Scan on lil_1  (cost=35.82..35.88 rows=3 width=8) (actual time=2.522..2.651 rows=390 loops=1)"
"                                                                                                    ->  HashAggregate  (cost=35.82..35.85 rows=3 width=8) (actual time=2.522..2.600 rows=390 loops=1)"
"                                                                                                          Group Key: "*SELECT* 1_2".locations_pk, "*SELECT* 1_2".inv_loc_pk"
"                                                                                                          ->  Append  (cost=0.14..35.81 rows=3 width=8) (actual time=2.207..2.334 rows=390 loops=1)"
"                                                                                                                ->  Result  (cost=0.14..34.78 rows=2 width=8) (actual time=2.207..2.304 rows=389 loops=1)"
"                                                                                                                      ->  HashSetOp Except  (cost=0.14..34.78 rows=2 width=8) (actual time=2.206..2.244 rows=389 loops=1)"
"                                                                                                                            ->  Append  (cost=0.14..34.77 rows=3 width=8) (actual time=0.048..1.986 rows=389 loops=1)"
"                                                                                                                                  ->  Subquery Scan on "*SELECT* 1_2"  (cost=0.14..33.75 rows=2 width=8) (actual time=0.048..1.954 rows=389 loops=1)"
"                                                                                                                                        ->  Nested Loop  (cost=0.14..33.73 rows=2 width=8) (actual time=0.047..1.889 rows=389 loops=1)"
"                                                                                                                                              ->  Seq Scan on locations l_3  (cost=0.00..2.37 rows=37 width=36) (actual time=0.005..0.020 rows=38 loops=1)"
"                                                                                                                                              ->  Index Scan using sidx_inv_loc_geom on inv_loc i_3  (cost=0.14..0.84 rows=1 width=36) (actual time=0.019..0.046 (...)"
"                                                                                                                                                    Index Cond: (geom && l_3.geom)"
"                                                                                                                                                    Filter: _st_intersects(geom, l_3.geom)"
"                                                                                                                                                    Rows Removed by Filter: 0"
"                                                                                                                                  ->  Subquery Scan on "*SELECT* 2_2"  (cost=0.00..1.02 rows=1 width=8) (actual time=0.005..0.005 rows=0 loops=1)"
"                                                                                                                                        ->  Seq Scan on loc_inv_adjust a_1  (cost=0.00..1.01 rows=1 width=8) (actual time=0.005..0.005 rows=0 loops=1)"
"                                                                                                                                              Filter: (include = 0)"
"                                                                                                                                              Rows Removed by Filter: 1"
"                                                                                                                ->  Seq Scan on loc_inv_adjust b_1  (cost=0.00..1.01 rows=1 width=8) (actual time=0.002..0.003 rows=1 loops=1)"
"                                                                                                                      Filter: (include = 1)"
"                                                          ->  Index Scan using bysampledescription on sample s_1  (cost=0.14..0.25 rows=1 width=8) (actual time=0.002..0.002 rows=1 loops=128)"
"                                                                Index Cond: (sample_description_pk = sd_1.sample_description_pk)"
"                                                    ->  Index Only Scan using inv_loc_pkey on inv_loc il_1  (cost=0.14..0.29 rows=1 width=4) (actual time=0.002..0.002 rows=1 loops=134)"
"                                                          Index Cond: (inv_loc_pk = i_2.inv_loc_pk)"
"                                                          Heap Fetches: 134"
"                                              ->  Index Only Scan using pk_locations on locations l_2  (cost=0.14..0.20 rows=1 width=4) (actual time=0.002..0.002 rows=1 loops=134)"
"                                                    Index Cond: (locations_pk = rc.locations_pk)"
"                                                    Heap Fetches: 134"
"                                  ->  Subquery Scan on "*SELECT* 2_1"  (cost=266.84..296.55 rows=914 width=106) (actual time=3.855..7.460 rows=1862 loops=1)"
"                                        ->  WindowAgg  (cost=266.84..287.41 rows=914 width=106) (actual time=3.853..7.089 rows=1862 loops=1)"
"                                              ->  Sort  (cost=266.84..269.13 rows=914 width=106) (actual time=3.844..3.959 rows=1862 loops=1)"
"                                                    Sort Key: ar.sample_pk, ar.analyte_pk, ar.result DESC"
"                                                    Sort Method: quicksort  Memory: 196kB"
"                                                    ->  Nested Loop  (cost=44.81..221.89 rows=914 width=106) (actual time=0.309..2.041 rows=1862 loops=1)"
"                                                          ->  Seq Scan on detected d  (cost=0.00..1.09 rows=1 width=8) (actual time=0.004..0.007 rows=3 loops=1)"
"                                                                Filter: (detected_yn = 1)"
"                                                                Rows Removed by Filter: 4"
"                                                          ->  Bitmap Heap Scan on analytical_results ar  (cost=44.81..199.48 rows=2133 width=106) (actual time=0.103..0.573 rows=621 loops=3)"
"                                                                Recheck Cond: (detected_pk = d.detected_pk)"
"                                                                Heap Blocks: exact=127"
"                                                                ->  Bitmap Index Scan on by_detected  (cost=0.00..44.28 rows=2133 width=0) (actual time=0.088..0.088 rows=665 loops=3)"
"                                                                      Index Cond: (detected_pk = d.detected_pk)"
"                                  ->  Subquery Scan on "*SELECT* 3"  (cost=266.84..298.83 rows=914 width=106) (actual time=5.384..8.761 rows=4238 loops=1)"
"                                        ->  WindowAgg  (cost=266.84..289.69 rows=914 width=106) (actual time=5.384..8.425 rows=4238 loops=1)"
"                                              ->  Sort  (cost=266.84..269.13 rows=914 width=106) (actual time=5.379..5.477 rows=4238 loops=1)"
"                                                    Sort Key: ar_1.sample_pk, ar_1.analyte_pk, ar_1.reporting_limit, ar_1.method_detection_limit"
"                                                    Sort Method: quicksort  Memory: 524kB"
"                                              

ype*_*eᵀᴹ 7

由于public.samples_exp_unitpublic.sample_results是视图,因此您在查询中添加了一个间接级别。

您可以重写为更简单:

WITH 
  eu AS (TABLE public.samples_exp_unit),
  sr AS (TABLE public.sample_results)
SELECT
  sr.sample_pk,
  eu.inventory_pk,
  .....
FROM sr INNER JOIN eu
  ON sr.sample_pk = eu.sample_pk ;
Run Code Online (Sandbox Code Playgroud)

并测试这是否会改变计划并提高效率。

要测试的另一件事是避免 CTE。特别是因为它们是优化栅栏,它们有时会导致效率较低的计划(有时会导致效率更高的计划!)在没有 CTE 的情况下重写和测试:

SELECT
  sr.sample_pk,
  eu.inventory_pk,
  .....
FROM public.sample_results AS sr 
  INNER JOIN 
     public.samples_exp_unit AS eu
  ON sr.sample_pk = eu.sample_pk ;
Run Code Online (Sandbox Code Playgroud)

还可以通过 psql 尝试查询。它将显示 PgAdmin 是否是问题所在。

可能是 pgAdmin 需要很长时间来呈现查询结果,或者正在通过慢速网络进行通信,因此需要很长时间才能获取结果。也有可能 pgAdmin 正在做一些改变执行计划的事情,比如默默地将一些参数设置为非默认值,或者在执行前将查询准备到游标中。