【问题标题】:Many to Many Table - Performance is bad多对多表 - 性能很差
【发布时间】:2017-09-19 13:28:49
【问题描述】:

给出了下表:

--- 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

每个玩家在桌面玩家中都有一行(带有他的属性)。同样,每个俱乐部在桌面俱乐部都有一个条目。 对于他职业生涯中的每个站点,球员在表 playerInClubs (n-m) 中都有一个条目,其中包含球员加入的日期以及球员离开俱乐部的时间。

我的主要问题是这些表的性能。在 Table player 中,我们有超过 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 在 table player 中直接选择一个团队的球员。

有人对我的数据库结构有一些性能提示以加快这些选择吗?

【问题讨论】:

  • Edit您的问题并添加使用explain (analyze, verbose)生成的执行计划。 Formatted textno screen shots
  • 您还想对 playersinclubs{player,date_joined+left} 进行日期范围限制吗?顺便说一句:你真的不需要桥接表上的代理键。
  • 缺少基本信息。考虑 [postgresql-performance] 标签信息中的说明。
  • 那么你有答案了吗?
  • 我已经添加了索引playersinclubs(club_id, player_id),但是性能差不多。也许没有办法提高此数据表的性能?...

标签: postgresql indexing many-to-many postgresql-performance


【解决方案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 进行 index-only 扫描,否则它可能是实质性的。

您可能也不需要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 和表格的所有列中的所有 个条目。但你的描述另有说明。查询和索引会有所不同。

密切相关的答案:

【讨论】:

    【解决方案2】:

    表格看起来很好,查询也很好。那么让我们看看查询应该做什么:

    1. 选择 ID 为 3 的俱乐部。一条可通过 PK 索引访问的记录。
    2. 选择俱乐部 ID 为 3 的所有 playerinclub 记录。因此我们需要从该列开始的索引。如果您没有,请创建它。

    我建议:

    create unique index idx_playersinclubs on playersinclubs(club_id, player_id, joined);
    

    这将是表的唯一业务键。我知道在许多具有技术 ID 的数据库中,这些唯一约束都没有建立,但我认为这是这些数据库中的一个缺陷,并且总是会创建这些约束/索引。

    1. 使用由此获得的玩家 ID 并相应地选择玩家。我们可以从 playerinclubs 记录中获取玩家 ID,但它也是我们索引中的第二列,因此 DBMS 可以选择其中一个来执行连接。 (它可能会使用索引中的列。)

    所以也许只是上面的索引还不存在。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-12-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-02-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多