提供以下表格:
--- player --
id serial
name VARCHAR(100)
birthday DATE
country VARCHAR(3)
PRIMARY KEY id
--- club ---
id SERIAL
name VARCHAR(100)
country VARCHAR(3)
PRIMARY KEY id
--- playersinclubs ---
id SERIAL
player_id INTEGER (with INDEX)
club_id INTEGER (with INDEX)
joined DATE
left DATE
PRIMARY KEY id
每个玩家在桌面播放器中都有一行(带有他的属性)。同样,每个俱乐部都有桌俱乐部的入场券。 对于他职业生涯中的每个站点,玩家都有一个表格玩家在俱乐部(n-m)中输入玩家加入的日期以及玩家离开俱乐部时的日期。
我的主要问题是这些表的性能。在桌面播放器中,我们有超过1000万条目。如果我想显示一个俱乐部的历史记录,所有球员都为这个俱乐部效力,我的选择如下:
SELECT * FROM player
JOIN playersinclubs ON player.id = playersinclubs.player_id
JOIN club ON club.id = playersinclubs.club_id
WHERE club.dbid = 3;
但是对于大量玩家来说,桌面播放器上的序列扫描将被执行。这种选择需要花费很多时间。
在我为我的应用程序实现一些新功能之前,每个玩家只有一个团队(只有今天的团队和玩家)。 所以我没有表球员俱乐部。相反,我在桌面播放器中有一个team_id。我可以使用where子句team_id = 3直接在桌面播放器中选择团队的玩家。
是否有人为我的数据库结构提供了一些性能提示以加快这些选择?
答案 0 :(得分:1)
最重要的是,您需要playersinclubs(club_id, player_id)
上的索引。其余的是细节(可能仍然有很大的不同)
您需要准确了解自己的实际目标。你写道:
所有球员都为这个俱乐部效力:
您根本不需要加入club
:
SELECT p.*
FROM playersinclubs pc
JOIN player p ON p.id = pc.player_id
WHERE pc.club_id = 3;
您在输出中也不需要列playersinclubs
,这对性能来说只是一小部分 - 除非它允许playersinclubs
上的仅索引扫描,然后它可能是实质性的。
您可能不需要在结果中所有列player
。只有SELECT
您实际需要的列。
player
上的PK提供了该表所需的索引。
您需要playersinclubs(club_id, player_id)
上的索引,但不使其唯一,除非玩家不允许第二次加入同一个俱乐部。
如果玩家可以多次加入并且你只想要一个“所有玩家”列表,那么你还需要添加一个DISTINCT
步骤来折叠重复的条目。你可以:
SELECT DISTINCT p.* ...
但是,既然你正试图优化性能:早期消除欺骗会更便宜:
SELECT p.*
FROM (
SELECT DISTINCT player_id
FROM playersinclubs
WHERE club_id = 3;
) pc
JOIN player p ON p.id = pc.player_id;
也许您真的希望playersinclubs
中的所有条目以及表格的所有列。但你的描述不然。查询和索引会有所不同。
密切相关的答案:
答案 1 :(得分:0)
表格看起来很好,查询也是如此。因此,让我们看看查询应该做什么:
我建议:
create unique index idx_playersinclubs on playersinclubs(club_id, player_id, joined);
这将是表格中唯一的商业密钥。我知道在许多具有技术ID的数据库中没有建立这些独特的约束,但我认为这是这些数据库中的一个缺陷,并且总是会创建这些约束/索引。
所以也许只是上面的索引还不存在。