我将数据从SQL Server迁移到Postgres。
我正在更改我的表格结构以处理通用的体育比赛,但这给我带来了性能问题。
我有以下表格:
我使用以下查询选择所有匹配项:
SELECT * FROM matches AS m
INNER JOIN match_teams AS t ON m.id = t.match_id
INNER JOIN match_players AS p ON t.id = p.lineup_id
使用100k记录时,此查询大约需要6分钟:
-- Executing query:
SELECT * FROM matches AS m
INNER JOIN match_teams AS t ON m.id = t.match_id
INNER JOIN match_players AS p ON t.id = p.lineup_id
Total query runtime: 336360 ms.
1142078 rows retrieved.
在SQL Server上,我将所有这些数据放在一个表中,它将在不到5秒的时间内返回。在Postgres中,我还使用jsonb将这些数据放入1个表中,并且能够在40秒内运行上述查询。
如何更快地进行此查询?我想把它降到几秒钟。
在线阅读我发现创建索引可以加速这些连接。我做了以下索引:
CREATE INDEX match_teams_match_id_idx ON match_teams USING btree (match_id);
CREATE INDEX match_players_lineup_id_idx ON match_players USING btree (lineup_id);
CREATE INDEX match_players_player_id_idx ON match_players USING btree (player_id);
CREATE INDEX matches_id_idx ON matches USING btree (id);
这些索引根本无法让查询更快。我错过了吗?
这是以上查询的EXPLAIN ANALYZE VERBOSE输出:
"Hash Join (cost=19314.10..67893.04 rows=1135917 width=24) (actual time=401.225..1624.906 rows=1142078 loops=1)"
" Output: m.id, m.start_time, t.team_id, t.rank, p.player_id"
" Hash Cond: (p.lineup_id = t.id)"
" -> Seq Scan on public.match_players p (cost=0.00..19818.78 rows=1142078 width=8) (actual time=0.039..356.168 rows=1142078 loops=1)"
" Output: p.player_id, p.lineup_id"
" -> Hash (cost=15119.58..15119.58 rows=228442 width=24) (actual time=401.123..401.123 rows=228442 loops=1)"
" Output: m.id, m.start_time, t.team_id, t.rank, t.id"
" Buckets: 8192 Batches: 4 Memory Usage: 3358kB"
" -> Hash Join (cost=5097.97..15119.58 rows=228442 width=24) (actual time=74.766..310.864 rows=228442 loops=1)"
" Output: m.id, m.start_time, t.team_id, t.rank, t.id"
" Hash Cond: (t.match_id = m.id)"
" -> Seq Scan on public.match_teams t (cost=0.00..3519.42 rows=228442 width=16) (actual time=0.004..64.580 rows=228442 loops=1)"
" Output: t.team_id, t.rank, t.match_id, t.id"
" -> Hash (cost=3112.21..3112.21 rows=114221 width=12) (actual time=74.728..74.728 rows=114221 loops=1)"
" Output: m.id, m.start_time"
" Buckets: 16384 Batches: 2 Memory Usage: 2682kB"
" -> Seq Scan on public.matches m (cost=0.00..3112.21 rows=114221 width=12) (actual time=0.003..34.789 rows=114221 loops=1)"
" Output: m.id, m.start_time"
"Planning time: 0.448 ms"
"Execution time: 1799.412 ms"
更新
在此处添加DDL:http://pastie.org/10529040
更新2
Postgres正在AWS RDS服务器上运行。我尝试在干净的EC2服务器和干净的PGAdmin安装上运行上述查询。我得到了相同的结果,似乎在~2秒内运行查询但需要~6分钟才能显示数据。
更新3
我尝试从一个简单的C#程序运行此查询,结果在大约10秒内返回。这似乎是PGAdmin的一个问题。
答案 0 :(得分:1)
Postgres有一个非常智能的查询引擎。我使用Postgres,而且我经常从别人那里听说过Postgres的速度很慢" - 但我从来没有经历过这个。它可能没有其他DBMS可能具有的默认值,因此您只需要了解优化。
夫妻稳定点:
因为引擎"认为"就你自己而言,你经常需要告诉Postgres重新分析表格"一旦你把索引放在上面。此外,您有时需要"真空"得到任何"死" Postgres认为它有它的行。
为此,请执行:
vacuum [schema].[table_name];
analyze [schema].[table_name];
在将索引放在其上之后执行此操作,它应该可以大大加快查询执行速度。
注意:您不需要在PRIMARY KEY上放置索引,因为PRIMARY KEY CONSTRAINT会创建一个自动唯一INDEX。
只要你在match_teams表(id
)上有一个PRIMARY KEY约束,那么你应该只需要在match_teams表上放一个btree
索引,如下所示:
CREATE INDEX match_teams_match_id_idx ON match_teams USING btree (match_id);
答案 1 :(得分:0)
正如@a_horse_with_no_name和@David Aldridge指出的那样,查询在服务器上运行了大约2秒钟,但花了大约6分钟才真正在PGAdmin中显示结果。
我尝试从具有相同结果的AWS服务器(不同网络)运行相同的查询。
然后我尝试从一个简单的C#程序本地运行此查询,结果在大约10秒内返回。
这似乎是PGAdmin的一个问题。