我首先为标题道歉,但不能想出一个更好的方式来表达它 其次,我有下表:
Profiles Table: Primary Key: profileName <----- | Repositories Table: | Composite Primary Keys: (profileName, repository_name)
模拟个人资料表与存储库表之间的 1 - n 关系。 我最近发现jooq并使用它来检索和存储数据库中的数据,并使用此代码从db中检索配置文件:
profile = db.select().from(Profiles.PROFILES, Repositories.REPOSITORIES).fetch().stream()
.filter(t -> t.getValue(Profiles.PROFILES.PROFILENAME).equalsIgnoreCase(profileName))
.limit(1) //limit it to just the one result
.map(this::convertToProfile)
.collect(Collectors.toList()).get(0);
工作正常,但我不确定如何改进这一点以包括检索存储库表中的可能的存储库。也就是说,对于配置文件表,存储库不是强制性的而是可选的。 我现在唯一的选择是创建一个第二周期逻辑&#39;在解组数据之前使用配置文件名称检索存储库。
答案 0 :(得分:3)
随着数据的增长,您的查询速度会非常慢。为什么?因为您的SQL查询仅在PROFILES
和REPOSITORIES
表之间运行cartesian product,而连接谓词和限制子句则应用于Java内存。
数据库永远不知道你想对这个交叉产品做什么,所以它非常愚蠢地运行这个非常慢的查询。如果通过“将谓词向下推”到jOOQ / SQL查询中为数据库提供更多信息,整个过程将运行得更快(尽管流结果在技术上是等效的)。所以,请写下这个:
profile = db.select()
.from(PROFILES, REPOSITORIES)
// WHERE and LIMIT are moved "up" into the SQL query:
.where(PROFILES.PROFILENAME.equalIgnoreCase(profileName))
.limit(1)
.fetch().stream()
.map(this::convertToProfile)
.collect(Collectors.toList()).get(0);
此查询与您的查询相同(尚未更正),但更快
上述查询仍在两个表之间运行笛卡尔积。你可能想加入他们。在SQL中有两种加入方式:
WHERE
子句只需在where子句中添加JOIN
谓词即可设置
profile = db.select()
.from(PROFILES, REPOSITORIES)
// Join predicate here:
.where(PROFILES.PROFILENAME.equal(REPOSITORIES.PROFILENAME))
.and(PROFILES.PROFILENAME.equalIgnoreCase(profileName))
.limit(1)
.fetch().stream()
.map(this::convertToProfile)
.collect(Collectors.toList()).get(0);
这也称为INNER JOIN
,可以使用JOIN
子句编写,以提高可读性:
(INNER) JOIN
子句:大多数人会发现这种语法更具可读性,因为JOIN
谓词与“普通”谓词明显分开:
profile = db.select()
.from(PROFILES)
// Join expression and predicates here:
.join(REPOSITORIES)
.on(PROFILES.PROFILENAME.equal(REPOSITORIES.PROFILENAME))
// Ordinary predicates remain in the where clause:
.where(PROFILES.PROFILENAME.equalIgnoreCase(profileName))
.limit(1)
.fetch().stream()
.map(this::convertToProfile)
.collect(Collectors.toList()).get(0);
JOIN
在SQL中,这称为OUTER JOIN
,或者更具体地称为LEFT (OUTER) JOIN
:
profile = db.select()
.from(PROFILES)
// LEFT JOIN expression and predicates here:
.leftJoin(REPOSITORIES)
.on(PROFILES.PROFILENAME.equal(REPOSITORIES.PROFILENAME))
.where(PROFILES.PROFILENAME.equalIgnoreCase(profileName))
.limit(1)
.fetch().stream()
.map(this::convertToProfile)
.collect(Collectors.toList()).get(0);
请注意,REPOSITORIES
列表不会为空,但包含一个存储库,其所有值都设置为NULL
。这就是OUTER JOIN
的工作方式