SQL表连接多对多非常慢

时间:2016-03-15 07:53:10

标签: sql performance postgresql join many-to-many

使用PostgreSQL,我在一个查询中加入了大约10个表,所有这些表都是多对多的关系。目前数据库仍然非常小(总共数百行,所有表合并),但查询速度极慢(处理时间超过1分钟)。

当每个连接乘以行数(连接2个具有5个记录的表,每个将产生25行)时,结果很快就会超过300,000行。查询采用以下形式:

select * from student_profile sp
  join student_profile_skills sps on sp.id = sps.student_profile_id
  join student_profile_hobby sph on sp.id = sph.student_profile_id
  --and other 8 similar joins
  where sp.id = 1;

表格很简单(有2个FK的联结表)。这里的推荐做法是什么?它是必须以更优化的方式编写的查询,还是使用单独的查询? Thx提前!

其他信息:


CREATE TABLE student_profile
(
  id                       serial  NOT NULL,
  first_name               text    NOT NULL,
  last_name                text    NOT NULL,
  country_id               integer,
  city_id                  integer,
  faculty_id               integer,
  university_id            integer,
  degree_id                integer,
  degree_year              integer,
  created_at               timestamp with time zone NOT NULL DEFAULT CURRENT_TIMESTAMP,
  updated_at               timestamp with time zone NOT NULL DEFAULT CURRENT_TIMESTAMP,
  CONSTRAINT student_profile_pkey               PRIMARY KEY (id),
  CONSTRAINT student_profile_country_id_fkey    FOREIGN KEY (country_id)    REFERENCES country (id),
  CONSTRAINT student_profile_city_id_fkey       FOREIGN KEY (city_id)       REFERENCES city (id),
  CONSTRAINT student_profile_faculty_id_fkey    FOREIGN KEY (faculty_id)    REFERENCES faculty (id),
  CONSTRAINT student_profile_university_id_fkey FOREIGN KEY (university_id) REFERENCES university (id),
  CONSTRAINT student_profile_degree_id_fkey     FOREIGN KEY (degree_id)     REFERENCES degree (id)
);

CREATE TABLE student_profile_skill
(
  id                 serial                   NOT NULL,
  student_profile_id integer                  NOT NULL,
  skill_id           integer                  NOT NULL,
  position           integer                  NOT NULL,
  created_at         timestamp with time zone NOT NULL DEFAULT CURRENT_TIMESTAMP,
  updated_at         timestamp with time zone NOT NULL DEFAULT CURRENT_TIMESTAMP,
  CONSTRAINT student_profile_skill_pkey                    PRIMARY KEY (id),
  CONSTRAINT student_profile_skill_student_profile_id_fkey FOREIGN KEY (student_profile_id) REFERENCES student_profile (id),
  CONSTRAINT student_profile_skill_skill_id_fkey           FOREIGN KEY (skill_id)           REFERENCES skill (id),
  CONSTRAINT student_profile_skill_unique                  UNIQUE (student_profile_id, skill_id),
  CONSTRAINT student_profile_skill_position_unique         UNIQUE (student_profile_id, position)
);

1 个答案:

答案 0 :(得分:0)

几乎所有多对多连接中的推荐做法是将它们分成一对多/多对一。但是,如果您的学生拥有超过1个技能/爱好,则您在3方式联接中拥有1对多的表格会导致大量重复记录。

3人加入的例子,你有1名学生有2个技能和1个爱好:

Student     Skill       Hobby  
Smith J.    Linguistic  Fishing  
Smith J.    Profiling   Fishing

我建议2个选项之一:

  1. 只有在您需要时选择您需要的值,(因为我无法想象您需要一张既有爱好又有技巧的表。例如:爱好和技能的独立视图。
  2. 为临时表创建一个脚本,将所有技能写入1个字段,将所有爱好写入另一个字段。 (你可能需要使用游标来构建它们,所以请记住,你不想经常重建游标)。