Как улучшить PostgreSQL время выполнения запроса? - PullRequest
0 голосов
/ 02 марта 2020

Итак, я хочу улучшить время выполнения запроса, которое занимает около 90 мсек c, наихудший случай - около 150 мсек c. В основном мне нужно получить текущую (в этом сезоне) статистику для каждой команды НБА. Примерно так -> https://stats.nba.com/teams/traditional/?sort=W_PCT&dir=-1 кроме (MIN, BLKA, PFD).

Столбцы в таблице player_stats: id, идентификатор_игры, идентификатор_команды, идентификатор_противника, идентификатор_проигрывателя, минуты, fg, fga, fga, fgp, fg3, fg3a, fg3p, ft, fta, ftp, orb, drb, trb, ast, stl , blk, tov, pf, pts, plus_minus, сезон, плей-офф.

Столбцы в таблице команд: id, team_name, short_name, other_names, ссылка, конференция.

Столбцы в таблице игр: id , home_team_id, home_team_score, away_team_id, away_team_score, дата, плей-офф, сезон.

У меня есть индексы и, насколько я знаю, они работают должным образом. Извините, если это вопрос для начинающих, но я не такой опыт написания запросов к базе данных.

SELECT 
    t.name AS team_name,
    CONCAT('/teams/', t.short_name) AS team_url,
    hg.hg + ag.ag AS tot_games,
    hg.home_game_wons + ag.away_game_wons AS games_won,
    hg.home_game_losses + ag.away_game_losses AS games_loss,
    ROUND(((hg.home_game_wons + ag.away_game_wons) / ROUND(hg.hg + ag.ag)) * 100, 2) AS w_l_p,
    ROUND(SUM(ps.fg) / ROUND(hg.hg + ag.ag), 1) AS fg,
    ROUND(SUM(ps.fga) / ROUND(hg.hg + ag.ag), 1) AS fga, 
    ROUND(avg(ps.fgp)::decimal * 100, 1) AS fgp, 
    ROUND(SUM(ps.fg3) / ROUND(hg.hg + ag.ag), 1) AS fg3, 
    ROUND(SUM(ps.fg3a) / ROUND(hg.hg + ag.ag), 1) AS fg3a, 
    ROUND(avg(ps.fg3p)::decimal *100,1) AS fg3p, 
    ROUND(SUM(ps.ft) / ROUND(hg.hg + ag.ag), 1) AS ft, 
    ROUND(SUM(ps.fta) / ROUND(hg.hg + ag.ag), 1) AS fta, 
    ROUND(avg(ps.ftp)::decimal * 100,1) AS ftp, 
    ROUND(SUM(ps.orb) / ROUND(hg.hg + ag.ag), 1) AS orb, 
    ROUND(SUM(ps.drb) / ROUND(hg.hg + ag.ag), 1) AS drb, 
    ROUND(SUM(ps.trb) / ROUND(hg.hg + ag.ag), 1) AS trb, 
    ROUND(SUM(ps.ast) / ROUND(hg.hg + ag.ag), 1) AS ast, 
    ROUND(SUM(ps.stl) / ROUND(hg.hg + ag.ag), 1) AS stl, 
    ROUND(SUM(ps.blk) / ROUND(hg.hg + ag.ag), 1) AS blk, 
    ROUND(SUM(ps.tov) / ROUND(hg.hg + ag.ag), 1) AS tov, 
    ROUND(SUM(ps.pf) / ROUND(hg.hg + ag.ag), 1) AS pf, 
    ROUND(SUM(ps.pts) / ROUND(hg.hg + ag.ag), 1) AS pts,
    ROUND((hg.home_opponent_scored + ag.away_opponent_scored) / ROUND(hg.hg + ag.ag), 1) AS opponent_pts
FROM public.player_stats AS ps
LEFT JOIN public.teams AS t
    ON ps.team_id = t.id
LEFT JOIN (
    SELECT `enter code here`
    home_team_id,
    COUNT(
        CASE 
           WHEN home_team_score > away_team_score THEN 1
        END
    ) AS home_game_wons,
    COUNT(
        CASE 
           WHEN home_team_score < away_team_score THEN 1
        END
    ) AS home_game_losses,
    SUM(away_team_score) AS home_opponent_scored,
    COUNT(home_team_id)::decimal AS hg
    FROM public.games
    WHERE season = '2019-20' AND playoff = false 
    GROUP BY home_team_id
) AS hg
    ON ps.team_id = hg.home_team_id
LEFT JOIN (
    SELECT 
    away_team_id,
    COUNT(
        CASE 
           WHEN home_team_score < away_team_score THEN 1
        END
    ) AS away_game_wons,
    COUNT(
        CASE 
           WHEN home_team_score > away_team_score THEN 1
        END
    ) AS away_game_losses,
    SUM(home_team_score) AS away_opponent_scored,
    COUNT(away_team_id)::int AS ag
    FROM public.games
    WHERE season = '2019-20' AND playoff = false
    GROUP BY away_team_id
) as ag
    ON ps.team_id = ag.away_team_id
WHERE ps.season = '2019-20' AND ps.playoff = false
GROUP BY 
    t.name, 
    t.short_name, 
    hg.home_game_wons, 
    hg.home_game_losses,
    hg.home_opponent_scored,
    ag.away_game_wons, 
    ag.away_game_losses,
    ag.away_opponent_scored,
    hg.hg,
    ag.ag
ORDER BY games_won DESC, games_loss ASC;

EXPLAIN |

первые 29 строк

следующие 28 строк

введите описание изображения здесь

Sort  (cost=45826.48..45873.10 rows=18648 width=852) (actual time=51.570..51.575 rows=30 loops=1)
  Sort Key: ((hg.home_game_wons + ag.away_game_wons)) DESC, ((hg.home_game_losses + ag.away_game_losses))
  Sort Method: quicksort  Memory: 40kB
  Buffers: shared hit=1031 read=247
  ->  Finalize GroupAggregate  (cost=28708.80..37489.71 rows=18648 width=852) (actual time=39.190..51.507 rows=30 loops=1)
        Group Key: t.name, t.short_name, hg.home_game_wons, hg.home_game_losses, hg.home_opponent_scored, ag.away_game_wons, ag.away_game_losses, ag.away_opponent_scored, hg.hg, ag.ag
        Buffers: shared hit=1031 read=247
        ->  Gather Merge  (cost=28708.80..30847.76 rows=10969 width=348) (actual time=38.346..50.761 rows=57 loops=1)
              Workers Planned: 1
              Workers Launched: 1
              Buffers: shared hit=2014 read=342
              ->  Partial GroupAggregate  (cost=27708.79..28613.74 rows=10969 width=348) (actual time=33.335..44.570 rows=28 loops=2)
                    Group Key: t.name, t.short_name, hg.home_game_wons, hg.home_game_losses, hg.home_opponent_scored, ag.away_game_wons, ag.away_game_losses, ag.away_opponent_scored, hg.hg, ag.ag
                    Buffers: shared hit=2014 read=342
                    ->  Sort  (cost=27708.79..27736.22 rows=10969 width=216) (actual time=32.724..33.952 rows=10609 loops=2)
                          Sort Key: t.name, t.short_name, hg.home_game_wons, hg.home_game_losses, hg.home_opponent_scored, ag.away_game_wons, ag.away_game_losses, ag.away_opponent_scored, hg.hg, ag.ag
                          Sort Method: quicksort  Memory: 3275kB
                          Worker 0:  Sort Method: quicksort  Memory: 2665kB
                          Buffers: shared hit=2014 read=342
                          ->  Hash Left Join  (cost=2077.34..26972.71 rows=10969 width=216) (actual time=0.986..15.344 rows=10609 loops=2)
                                Hash Cond: (ps.team_id = t.id)
                                Buffers: shared hit=1988 read=342
                                ->  Merge Left Join  (cost=2060.14..26926.34 rows=10969 width=172) (actual time=0.926..12.449 rows=10609 loops=2)
                                      Merge Cond: (ps.team_id = ag.away_team_id)
                                      Buffers: shared hit=1981 read=342
                                      ->  Merge Left Join  (cost=1030.29..25759.18 rows=10969 width=144) (actual time=0.554..9.803 rows=10609 loops=2)
                                            Merge Cond: (ps.team_id = hg.home_team_id)
                                            Buffers: shared hit=1941 read=342
                                            ->  Parallel Index Scan using IDX__PLAYER_STATS_1 on player_stats ps  (cost=0.43..24592.03 rows=10969 width=88) (actual time=0.066..5.746 rows=10609 loops=2)
                                                  Index Cond: (((season)::text = '2019-20'::text) AND (playoff = false))
                                                  Buffers: shared hit=1906 read=336
                                            ->  Sort  (cost=1029.86..1029.95 rows=37 width=60) (actual time=0.483..0.493 rows=30 loops=2)
                                                  Sort Key: hg.home_team_id
                                                  Sort Method: quicksort  Memory: 27kB
                                                  Worker 0:  Sort Method: quicksort  Memory: 27kB
                                                  Buffers: shared hit=35 read=6
                                                  ->  Subquery Scan on hg  (cost=1028.06..1028.89 rows=37 width=60) (actual time=0.454..0.464 rows=30 loops=2)
                                                        Buffers: shared hit=35 read=6
                                                        ->  HashAggregate  (cost=1028.06..1028.52 rows=37 width=60) (actual time=0.452..0.460 rows=30 loops=2)
                                                              Group Key: games.home_team_id
                                                              Buffers: shared hit=35 read=6
                                                              ->  Bitmap Heap Scan on games  (cost=24.94..1013.50 rows=832 width=12) (actual time=0.113..0.282 rows=847 loops=2)
                                                                    Recheck Cond: ((season)::text = '2019-20'::text)
                                                                    Filter: (NOT playoff)
                                                                    Heap Blocks: exact=14
                                                                    Buffers: shared hit=35 read=6
                                                                    ->  Bitmap Index Scan on IDX__GAMES_2  (cost=0.00..24.73 rows=832 width=0) (actual time=0.098..0.099 rows=847 loops=2)
                                                                          Index Cond: (((season)::text = '2019-20'::text) AND (playoff = false))
                                                                          Buffers: shared hit=7 read=6
                                      ->  Sort  (cost=1029.86..1029.95 rows=37 width=32) (actual time=0.369..0.373 rows=30 loops=2)
                                            Sort Key: ag.away_team_id
                                            Sort Method: quicksort  Memory: 27kB
                                            Worker 0:  Sort Method: quicksort  Memory: 27kB
                                            Buffers: shared hit=40
                                            ->  Subquery Scan on ag  (cost=1028.06..1028.89 rows=37 width=32) (actual time=0.350..0.355 rows=30 loops=2)
                                                  Buffers: shared hit=40
                                                  ->  HashAggregate  (cost=1028.06..1028.52 rows=37 width=32) (actual time=0.349..0.353 rows=30 loops=2)
                                                        Group Key: games_1.away_team_id
                                                        Buffers: shared hit=40
                                                        ->  Bitmap Heap Scan on games games_1  (cost=24.94..1013.50 rows=832 width=12) (actual time=0.068..0.197 rows=847 loops=2)
                                                              Recheck Cond: ((season)::text = '2019-20'::text)
                                                              Filter: (NOT playoff)
                                                              Heap Blocks: exact=14
                                                              Buffers: shared hit=40
                                                              ->  Bitmap Index Scan on IDX__GAMES_2  (cost=0.00..24.73 rows=832 width=0) (actual time=0.062..0.062 rows=847 loops=2)
                                                                    Index Cond: (((season)::text = '2019-20'::text) AND (playoff = false))
                                                                    Buffers: shared hit=12
                                ->  Hash  (cost=13.20..13.20 rows=320 width=52) (actual time=0.039..0.040 rows=37 loops=2)
                                      Buckets: 1024  Batches: 1  Memory Usage: 11kB
                                      Buffers: shared hit=4
                                      ->  Seq Scan on teams t  (cost=0.00..13.20 rows=320 width=52) (actual time=0.024..0.031 rows=37 loops=2)
                                            Buffers: shared hit=4
Planning Time: 1.586 ms
Execution Time: 51.999 ms

...