【问题标题】:How can I optimize this query with multiple joins?如何使用多个联接优化此查询?
【发布时间】:2022-01-27 21:16:07
【问题描述】:

我使用的是 PostgreSQL 14.1。我的查询如下所示:

SELECT stats_game.id AS stats_game_id,
       stats_fighters.left_fighter AS stats_fighters_left_fighter,
       stats_fighters.right_fighter AS stats_fighters_right_fighter,
       stats_timestamp.ts AS stats_timestamp_ts,
       stats_timestamp.time_of_day AS stats_timestamp_time_of_day,
       stats_coefs.wl AS stats_coefs_wl,
       stats_coefs.wr AS stats_coefs_wr,
       stats_coefs.wlr AS stats_coefs_wlr,
       stats_coefs.wrr AS stats_coefs_wrr,
       stats_coefs.f AS stats_coefs_f,
       stats_coefs.b AS stats_coefs_b,
       stats_coefs.r AS stats_coefs_r,
       stats_coefs.flaw AS stats_coefs_flaw,
       stats_rounds.one AS stats_rounds_one,
       stats_rounds.two AS stats_rounds_two,
       stats_rounds.three AS stats_rounds_three,
       stats_rounds.four AS stats_rounds_four,
       stats_rounds.five AS stats_rounds_five,
       stats_rounds.six AS stats_rounds_six,
       stats_rounds.seven AS stats_rounds_seven,
       stats_rounds.eight AS stats_rounds_eight,
       stats_rounds.nine AS stats_rounds_nine,
       stats_roundsview.one_view AS stats_roundsview_one_view,
       stats_roundsview.two_view AS stats_roundsview_two_view,
       stats_roundsview.three_view AS stats_roundsview_three_view,
       stats_roundsview.four_view AS stats_roundsview_four_view,
       stats_roundsview.five_view AS stats_roundsview_five_view,
       stats_roundsview.six_view AS stats_roundsview_six_view,
       stats_roundsview.seven_view AS stats_roundsview_seven_view,
       stats_roundsview.eight_view AS stats_roundsview_eight_view,
       stats_roundsview.nine_view AS stats_roundsview_nine_view,
       stats_roundsviewfinish.one_view_f AS stats_roundsviewfinish_one_view_f,
       stats_roundsviewfinish.two_view_f AS stats_roundsviewfinish_two_view_f,
       stats_roundsviewfinish.three_view_f AS stats_roundsviewfinish_three_view_f,
       stats_roundsviewfinish.four_view_f AS stats_roundsviewfinish_four_view_f,
       stats_roundsviewfinish.five_view_f AS stats_roundsviewfinish_five_view_f,
       stats_roundsviewfinish.six_view_f AS stats_roundsviewfinish_six_view_f,
       stats_roundsviewfinish.seven_view_f AS stats_roundsviewfinish_seven_view_f,
       stats_roundsviewfinish.eight_view_f AS stats_roundsviewfinish_eight_view_f,
       stats_roundsviewfinish.nine_view_f AS stats_roundsviewfinish_nine_view_f,
       stats_finishes.one_f AS stats_finishes_one_f,
       stats_finishes.two_f AS stats_finishes_two_f,
       stats_finishes.three_f AS stats_finishes_three_f,
       stats_finishes.four_f AS stats_finishes_four_f,
       stats_finishes.five_f AS stats_finishes_five_f,
       stats_finishes.six_f AS stats_finishes_six_f,
       stats_finishes.seven_f AS stats_finishes_seven_f,
       stats_finishes.eight_f AS stats_finishes_eight_f,
       stats_finishes.nine_f AS stats_finishes_nine_f,
       stats_score.first_score AS stats_score_first_score,
       stats_score.second_score AS stats_score_second_score,
       stats_score.is_rusk AS stats_score_is_rusk,
       stats_roundstime.first_t AS stats_roundstime_first_t,
       stats_roundstime.second_t AS stats_roundstime_second_t,
       stats_roundstime.third_t AS stats_roundstime_third_t,
       stats_roundstime.fourth_t AS stats_roundstime_fourth_t,
       stats_roundstime.fifth_t AS stats_roundstime_fifth_t,
       stats_roundstime.sixth_t AS stats_roundstime_sixth_t,
       stats_roundstime.seventh_t AS stats_roundstime_seventh_t,
       stats_roundstime.eighth_t AS stats_roundstime_eighth_t,
       stats_roundstime.ninth_t AS stats_roundstime_ninth_t,
       stats_roundtime.min_time AS stats_roundtime_min_time,
       stats_roundtime.mean_time AS stats_roundtime_mean_time,
       stats_roundtime.max_time AS stats_roundtime_max_time,
       stats_timecoef.min_coef_less AS stats_timecoef_min_coef_less,
       stats_timecoef.mean_coef_less AS stats_timecoef_mean_coef_less,
       stats_timecoef.max_coef_less AS stats_timecoef_max_coef_less,
       stats_timecoef.min_coef_more AS stats_timecoef_min_coef_more,
       stats_timecoef.mean_coef_more AS stats_timecoef_mean_coef_more,
       stats_timecoef.max_coef_more AS stats_timecoef_max_coef_more,
       stats_totals.five_total_more AS stats_totals_five_total_more,
       stats_totals.five_total_less AS stats_totals_five_total_less,
       stats_totals.six_total_more AS stats_totals_six_total_more,
       stats_totals.six_total_less AS stats_totals_six_total_less,
       stats_totals.seven_total_more AS stats_totals_seven_total_more,
       stats_totals.seven_total_less AS stats_totals_seven_total_less,
       stats_totals.eight_total_more AS stats_totals_eight_total_more,
       stats_totals.eight_total_less AS stats_totals_eight_total_less
FROM stats_game
JOIN stats_fighters ON stats_game.id = stats_fighters.game_id
JOIN stats_timestamp ON stats_game.id = stats_timestamp.game_id
JOIN stats_coefs ON stats_game.id = stats_coefs.game_id
JOIN stats_rounds ON stats_game.id = stats_rounds.game_id
JOIN stats_roundsview ON stats_game.id = stats_roundsview.game_id
JOIN stats_roundsviewfinish ON stats_game.id = stats_roundsviewfinish.game_id
JOIN stats_finishes ON stats_game.id = stats_finishes.game_id
JOIN stats_score ON stats_game.id = stats_score.game_id
JOIN stats_roundstime ON stats_game.id = stats_roundstime.game_id
JOIN stats_roundtime ON stats_game.id = stats_roundtime.game_id
JOIN stats_timecoef ON stats_game.id = stats_timecoef.game_id
JOIN stats_totals ON stats_game.id = stats_totals.game_id
ORDER BY stats_game.id DESC LIMIT 200

这是解释结果:

 Limit  (cost=3.71..141.01 rows=200 width=413) (actual time=0.263..4.807 rows=200 loops=1)
  Buffers: shared hit=608
  ->  Merge Join  (cost=3.71..7140.27 rows=10395 width=413) (actual time=0.262..4.754 rows=200 loops=1)
        Merge Cond: (stats_game.id = stats_score.game_id)
        Buffers: shared hit=608
        ->  Merge Join  (cost=3.42..7228.43 rows=11490 width=448) (actual time=0.245..4.364 rows=200 loops=1)
              Merge Cond: (stats_game.id = stats_totals.game_id)
              Buffers: shared hit=572
              ->  Merge Join  (cost=3.14..7202.47 rows=12700 width=380) (actual time=0.230..3.939 rows=200 loops=1)
                    Merge Cond: (stats_game.id = stats_timecoef.game_id)
                    Buffers: shared hit=500
                    ->  Merge Join  (cost=2.85..6409.88 rows=12700 width=328) (actual time=0.215..3.520 rows=200 loops=1)
                          Merge Cond: (stats_game.id = stats_roundtime.game_id)
                          Buffers: shared hit=421
                          ->  Merge Join  (cost=2.57..5665.95 rows=12700 width=300) (actual time=0.199..3.109 rows=200 loops=1)
                                Merge Cond: (stats_game.id = stats_roundstime.game_id)
                                Buffers: shared hit=347
                                ->  Merge Join  (cost=2.28..4906.03 rows=12700 width=260) (actual time=0.181..2.714 rows=200 loops=1)
                                      Merge Cond: (stats_game.id = stats_roundsview.game_id)
                                      Buffers: shared hit=318
                                      ->  Merge Join  (cost=2.00..4680.43 rows=14037 width=233) (actual time=0.154..2.256 rows=200 loops=1)
                                            Merge Cond: (stats_game.id = stats_roundsviewfinish.game_id)
                                            Buffers: shared hit=251
                                            ->  Merge Join  (cost=1.71..4384.11 rows=15515 width=190) (actual time=0.130..1.861 rows=200 loops=1)
                                                  Merge Cond: (stats_game.id = stats_finishes.game_id)
                                                  Buffers: shared hit=222
                                                  ->  Merge Join  (cost=1.43..3620.00 rows=15515 width=168) (actual time=0.116..1.447 rows=200 loops=1)
                                                        Merge Cond: (stats_game.id = stats_rounds.game_id)
                                                        Buffers: shared hit=152
                                                        ->  Merge Join  (cost=1.14..2824.88 rows=15515 width=128) (actual time=0.097..1.101 rows=200 loops=1)
                                                              Merge Cond: (stats_game.id = stats_coefs.game_id)
                                                              Buffers: shared hit=123
                                                              ->  Merge Join  (cost=0.86..1967.77 rows=15515 width=60) (actual time=0.069..0.747 rows=200 loops=1)
                                                                    Merge Cond: (stats_game.id = stats_timestamp.game_id)
                                                                    Buffers: shared hit=74
                                                                    ->  Merge Join  (cost=0.57..1203.66 rows=15515 width=40) (actual time=0.043..0.434 rows=200 loops=1)
                                                                          Merge Cond: (stats_game.id = stats_fighters.game_id)
                                                                          Buffers: shared hit=38
                                                                          ->  Index Only Scan Backward using stats_game_pkey on stats_game  (cost=0.29..413.33 rows=15536 width=4) (actual time=0.025..0.090 rows=200 loops=1)
                                                                                Heap Fetches: 0
                                                                                Buffers: shared hit=4
                                                                          ->  Index Scan Backward using stats_fighters_game_id_5873ae20 on stats_fighters  (cost=0.29..557.56 rows=15515 width=36) (actual time=0.013..0.148 rows=200 loops=1)
                                                                                Buffers: shared hit=34
                                                                    ->  Index Scan Backward using stats_timestamp_game_id_7cba64ec on stats_timestamp  (cost=0.29..531.34 rows=15536 width=20) (actual time=0.023..0.133 rows=200 loops=1)
                                                                          Buffers: shared hit=36
                                                              ->  Index Scan Backward using stats_coefs_game_id_4945e660 on stats_coefs  (cost=0.29..624.33 rows=15536 width=68) (actual time=0.026..0.144 rows=200 loops=1)
                                                                    Buffers: shared hit=49
                                                        ->  Index Scan Backward using stats_rounds_game_id_3021918d on stats_rounds  (cost=0.29..562.33 rows=15536 width=40) (actual time=0.017..0.125 rows=200 loops=1)
                                                              Buffers: shared hit=29
                                                  ->  Index Scan Backward using stats_finishes_game_id_2cae9f9f on stats_finishes  (cost=0.29..531.34 rows=15536 width=22) (actual time=0.011..0.147 rows=200 loops=1)
                                                        Buffers: shared hit=70
                                            ->  Index Scan Backward using stats_roundsviewfinish_game_id_4613fecf on stats_roundsviewfinish  (cost=0.29..523.43 rows=14056 width=43) (actual time=0.020..0.123 rows=200 loops=1)
                                                  Buffers: shared hit=29
                                      ->  Index Scan Backward using stats_roundsview_game_id_5e0e170b on stats_roundsview  (cost=0.29..499.15 rows=14056 width=27) (actual time=0.023..0.154 rows=200 loops=1)
                                            Buffers: shared hit=67
                                ->  Index Scan Backward using stats_roundstime_game_id_503d284c on stats_roundstime  (cost=0.29..562.34 rows=15536 width=40) (actual time=0.015..0.125 rows=200 loops=1)
                                      Buffers: shared hit=29
                          ->  Index Scan Backward using stats_roundtime_game_id_7bb54c53 on stats_roundtime  (cost=0.29..546.34 rows=15536 width=28) (actual time=0.012..0.140 rows=200 loops=1)
                                Buffers: shared hit=74
                    ->  Index Scan Backward using stats_timecoef_game_id_cee96f92 on stats_timecoef  (cost=0.29..595.00 rows=15536 width=52) (actual time=0.010..0.132 rows=200 loops=1)
                          Buffers: shared hit=79
              ->  Index Scan Backward using stats_totals_game_id_dc1ed7ed on stats_totals  (cost=0.29..566.14 rows=14056 width=68) (actual time=0.011..0.127 rows=200 loops=1)
                    Buffers: shared hit=72
        ->  Index Scan Backward using stats_score_game_id_a4e3e3f5 on stats_score  (cost=0.29..468.14 rows=14056 width=13) (actual time=0.012..0.117 rows=200 loops=1)
              Buffers: shared hit=36
Planning:
  Buffers: shared hit=786
Planning Time: 135.963 ms
Execution Time: 5.172 ms

这是我的索引:

 schemaname |       tablename        |                indexname                | tablespace |                                                  indexdef
------------+------------------------+-----------------------------------------+------------+-------------------------------------------------------------------------------------------------------------
 public     | stats_coefs            | stats_coefs_pkey                        |            | CREATE UNIQUE INDEX stats_coefs_pkey ON public.stats_coefs USING btree (id)
 public     | stats_fighters         | stats_fighters_pkey                     |            | CREATE UNIQUE INDEX stats_fighters_pkey ON public.stats_fighters USING btree (id)
 public     | stats_finishes         | stats_finishes_pkey                     |            | CREATE UNIQUE INDEX stats_finishes_pkey ON public.stats_finishes USING btree (id)
 public     | stats_game             | stats_game_pkey                         |            | CREATE UNIQUE INDEX stats_game_pkey ON public.stats_game USING btree (id)
 public     | stats_rounds           | stats_rounds_pkey                       |            | CREATE UNIQUE INDEX stats_rounds_pkey ON public.stats_rounds USING btree (id)
 public     | stats_roundstime       | stats_roundstime_pkey                   |            | CREATE UNIQUE INDEX stats_roundstime_pkey ON public.stats_roundstime USING btree (id)
 public     | stats_roundsview       | stats_roundsview_pkey                   |            | CREATE UNIQUE INDEX stats_roundsview_pkey ON public.stats_roundsview USING btree (id)
 public     | stats_roundsviewfinish | stats_roundsviewfinish_pkey             |            | CREATE UNIQUE INDEX stats_roundsviewfinish_pkey ON public.stats_roundsviewfinish USING btree (id)
 public     | stats_roundtime        | stats_roundtime_pkey                    |            | CREATE UNIQUE INDEX stats_roundtime_pkey ON public.stats_roundtime USING btree (id)
 public     | stats_score            | stats_score_pkey                        |            | CREATE UNIQUE INDEX stats_score_pkey ON public.stats_score USING btree (id)
 public     | stats_timecoef         | stats_timecoef_pkey                     |            | CREATE UNIQUE INDEX stats_timecoef_pkey ON public.stats_timecoef USING btree (id)
 public     | stats_timestamp        | stats_timestamp_pkey                    |            | CREATE UNIQUE INDEX stats_timestamp_pkey ON public.stats_timestamp USING btree (id)
 public     | stats_totals           | stats_totals_pkey                       |            | CREATE UNIQUE INDEX stats_totals_pkey ON public.stats_totals USING btree (id)
 public     | stats_coefs            | stats_coefs_game_id_4945e660            |            | CREATE INDEX stats_coefs_game_id_4945e660 ON public.stats_coefs USING btree (game_id)
 public     | stats_fighters         | stats_fighters_game_id_5873ae20         |            | CREATE INDEX stats_fighters_game_id_5873ae20 ON public.stats_fighters USING btree (game_id)
 public     | stats_finishes         | stats_finishes_game_id_2cae9f9f         |            | CREATE INDEX stats_finishes_game_id_2cae9f9f ON public.stats_finishes USING btree (game_id)
 public     | stats_rounds           | stats_rounds_game_id_3021918d           |            | CREATE INDEX stats_rounds_game_id_3021918d ON public.stats_rounds USING btree (game_id)
 public     | stats_roundstime       | stats_roundstime_game_id_503d284c       |            | CREATE INDEX stats_roundstime_game_id_503d284c ON public.stats_roundstime USING btree (game_id)
 public     | stats_roundsview       | stats_roundsview_game_id_5e0e170b       |            | CREATE INDEX stats_roundsview_game_id_5e0e170b ON public.stats_roundsview USING btree (game_id)
 public     | stats_roundsviewfinish | stats_roundsviewfinish_game_id_4613fecf |            | CREATE INDEX stats_roundsviewfinish_game_id_4613fecf ON public.stats_roundsviewfinish USING btree (game_id)
 public     | stats_roundtime        | stats_roundtime_game_id_7bb54c53        |            | CREATE INDEX stats_roundtime_game_id_7bb54c53 ON public.stats_roundtime USING btree (game_id)
 public     | stats_score            | stats_score_game_id_a4e3e3f5            |            | CREATE INDEX stats_score_game_id_a4e3e3f5 ON public.stats_score USING btree (game_id)
 public     | stats_timecoef         | stats_timecoef_game_id_cee96f92         |            | CREATE INDEX stats_timecoef_game_id_cee96f92 ON public.stats_timecoef USING btree (game_id)
 public     | stats_timestamp        | stats_timestamp_game_id_7cba64ec        |            | CREATE INDEX stats_timestamp_game_id_7cba64ec ON public.stats_timestamp USING btree (game_id)
 public     | stats_totals           | stats_totals_game_id_dc1ed7ed           |            | CREATE INDEX stats_totals_game_id_dc1ed7ed ON public.stats_totals USING btree (game_id)

我是优化查询方面的菜鸟,并不真正了解如何阅读此 EXPLAIN 语句。

有什么办法可以提高这个查询的速度吗?它通常需要大约 500 毫秒,这是巨大的。我想知道是否可以使用一些简单的优化,但也想知道是否有一种方法可以创建物化视图和触发器,还是不值得?

【问题讨论】:

  • 请显示EXPLAIN (ANALYZE, BUFFERS),而不仅仅是解释。这样我们就可以看到它在每个节点上实际找到了多少行,以及它预计会找到多少行,以及实际花费了多长时间。
  • @jjanes 不知道这个。完成。

标签: sql postgresql query-optimization


【解决方案1】:

您的执行时间是您投诉时间的百分之一。但是,您在 136 毫秒时的计划时间相当长(但仍然只有您抱怨的时间的三分之一)。您展示的这个计划/执行是否异常快,或者您认为这里显示的时间是典型案例的公平代表?

如果您经常运行此查询(如果需要 500 毫秒,您为什么还要关心?),那么您可以准备查询,这样就不需要为每次执行进行计划。执行此操作的详细信息取决于您的客户端语言和连接库。

【讨论】:

    猜你喜欢
    • 2017-03-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-15
    • 1970-01-01
    • 2023-03-12
    • 1970-01-01
    相关资源
    最近更新 更多