加入多个可能的表

时间:2014-05-27 11:37:58

标签: sql postgresql join polymorphic-associations

在此SQL Fiddle上考虑以下架构。正如您所看到的,它遵循用于建模多态关联的超可用模式。请记住,foo,bar和baz表在实际实现上彼此非常不同。

我面临的问题是我需要检索给定所有者的所有活动及其相应的目标,我的第一个想法是使用多个LEFT OUTER JOINS:

SELECT *
FROM activities
LEFT OUTER JOIN foo ON activities.target_id = foo.activitable_id
LEFT OUTER JOIN bar ON activities.target_id = bar.activitable_id
LEFT OUTER JOIN baz ON activities.target_id = baz.activitable_id
WHERE activities.owner_id = 1

这个查询很好考虑到我只加入3个表,每个表上有一行,但是当模式增长到8个连接时,每个表上有10k行,那么'对性能产生巨大影响。

所以我的问题是,有什么方法可以通过更快的查询实现我想要的目标吗?

2 个答案:

答案 0 :(得分:1)

不需要对性能产生巨大影响。您已经为每个表定义了一个数据结构,只有一个索引,主键上的索引。这意味着连接的效率低于它们的效率。

另外,根据您的结构,我不认为您希望在任何表格中重复activitable_id。因此,每个表应该定义如下:

CREATE TABLE foo (
  id serial primary key,
  name varchar(20),
  activitable_id int UNIQUE,
  FOREIGN KEY (activitable_id) REFERENCES activitables(id)
);

声明activitable_id是唯一的,解决了这两个问题,因为它会在列上创建一个唯一的索引,它既强制唯一性又应该提高性能。

答案 1 :(得分:1)

您可以在查询中使用的列上添加索引:

activities.target_id
foo.activitable_id
bar.activitable_id    
baz.activitable_id

如果您可以在任何表上应用任何过滤条件,那么性能也会更好,因为您将在较小的数据子集上运行。例如,

SELECT *
FROM activities
LEFT OUTER JOIN (SELECT * FROM foo WHERE name like 'A%') foo ON activities.target_id = foo.activitable_id --Filter applied to limit rows using the name
LEFT OUTER JOIN (SELECT * FROM bar WHERE id < 10) bar ON activities.target_id = bar.activitable_id --Filter applied to limit rows using id
LEFT OUTER JOIN (SELECT * FROM baz WHERE activitable_id = 1) baz ON activities.target_id = baz.activitable_id --Filter applied to limit rows using activitable_id
WHERE activities.owner_id = 1;