SQL table 加入多对多很慢
SQL table join many-to-many very slow
使用 PostgreSQL,我在一个查询中连接了大约 10 个表,它们都是多对多关系。目前数据库仍然很小(总共数百行,所有表合并),但查询非常慢(1+ min 处理时间)。
由于每个连接都会使行数成倍增加(连接 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 的联结表)。这里推荐的做法是什么?是必须以更优化的方式编写查询,还是使用单独的查询?提前致谢!
附加信息:
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)
);
几乎所有多对多连接的推荐做法是将它们拆分为 one-to-many/many-to-one。但是,如果您的学生有超过 1 个 skill/hobby.
3 路加入示例,其中您有 1 名学生具有 2 种技能和 1 种爱好:
Student Skill Hobby
Smith J. Linguistic Fishing
Smith J. Profiling Fishing
我会建议 2 个选项中的 1 个:
- 只有 select你需要的价值观,(因为我无法想象你需要一个table兼具爱好和技能. 例如:兴趣爱好和技能分开看。
- 为临时 table 创建一个脚本,将所有技能写到 1 个领域,将所有爱好写到另一个领域。 (您可能需要使用游标来构建它们,因此请记住您不想经常重建它们)。
使用 PostgreSQL,我在一个查询中连接了大约 10 个表,它们都是多对多关系。目前数据库仍然很小(总共数百行,所有表合并),但查询非常慢(1+ min 处理时间)。
由于每个连接都会使行数成倍增加(连接 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 的联结表)。这里推荐的做法是什么?是必须以更优化的方式编写查询,还是使用单独的查询?提前致谢!
附加信息:
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)
);
几乎所有多对多连接的推荐做法是将它们拆分为 one-to-many/many-to-one。但是,如果您的学生有超过 1 个 skill/hobby.
3 路加入示例,其中您有 1 名学生具有 2 种技能和 1 种爱好:
Student Skill Hobby
Smith J. Linguistic Fishing
Smith J. Profiling Fishing
我会建议 2 个选项中的 1 个:
- 只有 select你需要的价值观,(因为我无法想象你需要一个table兼具爱好和技能. 例如:兴趣爱好和技能分开看。
- 为临时 table 创建一个脚本,将所有技能写到 1 个领域,将所有爱好写到另一个领域。 (您可能需要使用游标来构建它们,因此请记住您不想经常重建它们)。