SQL Server表有100k记录,2个内部联接非常慢

时间:2015-11-04 13:52:21

标签: sql sql-server performance postgresql pgadmin

我将数据从SQL Server迁移到Postgres。

我正在更改我的表格结构以处理通用的体育比赛,但这给我带来了性能问题。

我有以下表格:

  • 匹配(id,start_time)
  • match_teams (id,match_id,team_id,score)
  • match_players (id,lineup_id,player_id),其中lineup_id是match_teams.id上的外键

我使用以下查询选择所有匹配项:

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的一个问题。

2 个答案:

答案 0 :(得分:1)

Postgres有一个非常智能的查询引擎。我使用Postgres,而且我经常从别人那里听说过Postgres的速度很慢" - 但我从来没有经历过这个。它可能没有其他DBMS可能具有的默认值,因此您只需要了解优化。

夫妻稳定点:

  • 所有表都应该有一个主键,并且需要一个CONSTRAINT作为PRIMARY KEY
  • 如果您在其上放置btree索引(如上所述),您正在加入的任何大型表,ORDER BYING,GROUP BYing将进行优化。

因为引擎"认为"就你自己而言,你经常需要告诉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的一个问题。