Postgresql 多对多表-性能很差

Postgresql 多对多表-性能很差,postgresql,indexing,many-to-many,postgresql-performance,Postgresql,Indexing,Many To Many,Postgresql Performance,下表列出: --- 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 INTEG

下表列出:

--- 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
每个玩家在表中都有一行玩家(带有他的属性)。同样地,每个俱乐部都有一个参加桌上俱乐部的项目。 对于球员职业生涯中的每一站,球员都会在table playersInClubs(n-m)中输入球员加入俱乐部的日期,也可以选择球员离开俱乐部的日期

我的主要问题是这些表的性能。在TablePlayer中,我们有超过1000万个条目。如果我想显示一个俱乐部的历史记录,其中所有球员都为该俱乐部效力,我的选择如下所示:

SELECT * FROM player
 JOIN playersinclubs ON player.id = playersinclubs.player_id
 JOIN club ON club.id = playersinclubs.club_id
WHERE club.dbid = 3;
但是对于大量的玩家,将在table player上执行序列扫描。这个选择需要很多时间

在我为我的应用程序实现一些新功能之前,每个玩家只有一个团队(只有今天的团队和玩家)。 所以我没有桌球运动员俱乐部。取而代之的是,我有一个乒乓球队员的球队id。我可以使用where子句team_id=3在table player中直接选择一个团队的球员


是否有人为我的数据库结构提供了一些性能提示来加速这些选择?

表看起来不错,查询也不错。让我们看看查询应该做什么:

  • 选择ID为3的俱乐部。一条可通过PK索引访问的记录
  • 选择俱乐部ID 3的所有球员俱乐部记录。所以我们需要一个从这个列开始的索引。如果你没有,就创建它
  • 我建议:

    create unique index idx_playersinclubs on playersinclubs(club_id, player_id, joined);
    
    这将是表的唯一业务密钥。我知道,在许多具有技术ID的数据库中,这些唯一的约束还没有建立,但我认为这是这些数据库中的缺陷,并且总是会创建这些约束/索引。
  • 使用由此获得的玩家ID并相应地选择玩家。我们可以从playersinclubs记录中获取播放器ID,但它也是索引中的第二列,因此DBMS可以选择其中一列来执行连接。(它可能会使用索引中的列。)

  • 因此,可能只是上述索引还不存在。

    最重要的是,您需要
    玩家俱乐部(俱乐部id,球员id)
    上的索引。剩下的是细节(可能仍然会有很大的不同)。
    你需要准确地说出你的实际目标。你写道:

    他的所有球员都为这家俱乐部效力:

    您根本不需要加入
    俱乐部

    SELECT p.* 
    FROM   playersinclubs pc
    JOIN   player         p ON p.id = pc.player_id
    WHERE  pc.club_id = 3;
    
    您也不需要在输出中使用列
    playersinclubs
    ,这对性能来说是一个小小的提升-除非它只允许对
    playersinclubs
    进行索引扫描,否则它可能会很重要

    您可能也不需要结果中所有
    player
    列。仅选择实际需要的列

    player
    上的主键提供该表所需的索引

    您需要在
    playersinclubs(俱乐部id,球员id)
    上建立一个索引,但是not必须使其唯一,除非球员不允许再次加入同一俱乐部

    如果玩家可以多次加入,而您只需要一个“所有玩家”列表,那么您还需要添加一个
    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
    中的所有条目以及表中的所有列。但你的描述不是这样的。查询和索引会有所不同

    密切相关的回答:


    请回答您的问题,并添加使用
    解释(分析,详细)
    生成的执行计划。请问,您是否还需要
    playersinclubs{player,date_joined+left}
    上的日期范围限制?顺便说一句:你并不真的需要桥接表上的代理键。基本信息丢失了。考虑[ PostgreSQL性能]标签信息中的指令。那么你有答案吗?我添加了索引PrimeService俱乐部(CulbGyID,PraseRyId),但性能大致相同。也许没有办法提高这个数据表的性能?。。。