2016-03-15 81 views
0

使用PostgreSQL,我在查询中加入约10桌,它们都是许多一对多的关系。数据库目前仍然非常小(总共数百行,所有表格组合在一起),但查询速度非常慢(1分钟以上的处理时间)。SQL表连接许多一对多很慢

由于每一个加入相乘的行数(接合具有5个记录2代表的每个将产生25行),其结果很快变得庞大与超过30万行。查询的格式如下:

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个FKs的联结表)。这里推荐的做法是什么?是查询必须以更优化的方式编写还是使用单独的查询? 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) 
); 
+0

你能表现出一定的查询和/或表的详细信息? –

+0

你需要给我们的表的DDL – sagi

+0

查询是形式:SELECT * FROM student_profile SP加入student_profile_skills SPS上sp.id = sps.student_profile_id上​​sp.id = sph.student_profile_id(和其他8种相似的加入student_profile_hobby SPH加入)其中sp.id = 1; – Thibaut

回答

0

在几乎所有的许多一对多连接,建议的做法是给他们上一个一对多拆分/多对一之一。但是,如果您的学生拥有超过1个技能/爱好,则您在3路加入中有1对多表格,导致疯狂数量为重复记录。的3路

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

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

我建议1 2的选项:

  1. 只有选择值你需要当你需要他们,(因为我无法想象,你需要一台既爱好和技能,例如:对于爱好和技能的独立意见
  2. 一个临时表创建一个脚本,你W¯¯把所有技能都融入到1个领域,并将所有爱好融入另一个领域。 (您可能需要使用光标来构建它们,因此请记住,您不需要经常重建它们)。
+0

Thx为您的回应!所以这意味着我应该使用单独的SQL查询(例如:select * from student_profile_skill where student_profile_id = 1)并将数据组装到后端代码(Node.js)中,而不是加入所有这些表? – Thibaut

+0

是的,除非你有一个非常具体的要求有重复记录(这是不可能的)。如果您将结果放入网站或软件中,您只需一次使用1个连接以特定形式显示结果,或者如果您需要单行显示1名学生的所有技能/兴趣,您需要创建另一个表格并使用光标在每个学生的新表格中创建一个条目,并在表格的相应字段中添加您的技能/兴趣的文本描述。 – Zero