mybatis nested select vs. 嵌套结果
mybatis nested select vs. nested results
我是mybatis的初级用户,不知道嵌套select和嵌套结果的区别是否是就像 sub-query 与 join 之间的区别一样,尤其是在性能上。或者它会做一些优化?
我用的是mybatis 3.4.7版本和oracle DB
这里有一个例子供参考:
private List<Post> posts;
<resultMap id="blogResult" type="Blog">
<collection property="posts" javaType="ArrayList" column="id"
ofType="Post" select="selectPostsForBlog"/>
</resultMap>
<select id="selectBlog" resultMap="blogResult">
SELECT * FROM BLOG WHERE ID = #{id}
</select>
<select id="selectPostsForBlog" resultType="Post">
SELECT * FROM POST WHERE BLOG_ID = #{id}
</select>
或
<select id="selectBlog" resultMap="blogResult">
select
B.id as blog_id,
B.title as blog_title,
B.author_id as blog_author_id,
P.id as post_id,
P.subject as post_subject,
P.body as post_body,
from Blog B
left outer join Post P on B.id = P.blog_id
where B.id = #{id}
</select>
<resultMap id="blogResult" type="Blog">
<id property="id" column="blog_id" />
<result property="title" column="blog_title"/>
<collection property="posts" ofType="Post">
<id property="id" column="post_id"/>
<result property="subject" column="post_subject"/>
<result property="body" column="post_body"/>
</collection>
</resultMap>
嵌套selectlike子查询是否还有N+1个问题?
对于哪一个在特定环境或条件下表现更好,您有什么建议或经验吗?非常感谢:).
首先是一点术语说明。 SQL中的子查询是查询的一部分,它本身就是一个查询,例如:
SELECT ProductName
FROM Product
WHERE Id IN (SELECT ProductId
FROM OrderItem
WHERE Quantity > 100)
在这种情况下,以下查询是子查询:
SELECT ProductId
FROM OrderItem
WHERE Quantity > 100
所以你在这里使用术语 "subquery" 不正确。在 mybatis 文档中使用术语 嵌套 select。
在mybatis中获取关联entities/collections有两种方式。这是 documentation 的相关部分:
Nested Select: By executing another mapped SQL statement that returns
the complex type desired. Nested Results: By using nested result
mappings to deal with repeating subsets of joined results.
当使用嵌套 select 时,mybatis 首先执行主查询(在你的情况下 selectBlog
),然后对每条记录执行另一个 select(因此名称 nested select
) 以获取关联的 Post
个实体。
当使用Nested results
时,只执行一个查询,但它已经加入了关联数据。所以mybatis map结果到object结构
在您的示例中返回单个 Blog
实体,因此当使用 nested select
时会执行两个查询,但在一般情况下(如果您将获得 Blog
的列表)你会遇到 N+1
问题。
现在让我们来处理性能问题。以下所有内容均假设查询已调整(因为没有丢失索引),您正在使用连接池,数据库已并置,基本上来说您的系统在所有其他方面都已调整。
谈到性能,没有唯一的正确答案,您的里程数可能会有所不同。您始终需要在您的设置中测试您的特定工作流程。考虑到影响性能的因素有很多,比如数据分布(想想 max/min/arg post 每个博客都有)、数据库中记录的大小(想想博客中数据字段的数量和大小以及 post)、数据库参数(如磁盘类型和速度、可用于数据集缓存的内存量等)可能没有单一的答案,只有随后的一些一般观察结果。
但是如果我们查看性能范围两端的案例,我们可以理解性能差异。希望看到 nested select
明显优于 join
的情况,反之亦然。
对于 collection 在大多数情况下获取连接应该更好,因为执行 N+1
请求计数的网络延迟。
nested select
可能更好的一种情况是 one-to-many 关联,当主 table 中的记录引用其他一些 table 和其他 one-to-many 的基数时=87=] 不大,而另一个 table 中的记录大小很大。
例如,让我们考虑 Blog
有一个 category
属性 引用 categories
table 并且它可能具有以下值之一 Science, Fashion, News
.让我们想象一下博客列表是 select 由博客标题中的关键字等过滤器编辑的。如果结果包含比方说 500 个项目,那么大多数相关类别将是重复的。
如果我们 select 他们加入结果集中的每条记录将包含 Category
数据字段(提醒一下,其中大部分都是重复的,我们在 Category
记录).
如果我们select他们使用嵌套select,我们会为每条记录做查询以通过类别ID获取类别,这里mybatis session缓存开始发挥作用。在 SqlSession
期间,每次 mybatis 执行查询时,它会将其结果存储在 session 缓存中,因此它不会对数据库执行重复请求,而是从缓存中获取它们。这意味着在 mybatis 通过 id 为第一条记录检索到某个类别后,它将对其处理的记录集中的所有其他记录重用它。
在上面的示例中,我们将对数据库执行最多 4 个请求,但通过网络传递的数据量减少可能会增加执行 4 个请求的需求。
我是mybatis的初级用户,不知道嵌套select和嵌套结果的区别是否是就像 sub-query 与 join 之间的区别一样,尤其是在性能上。或者它会做一些优化?
我用的是mybatis 3.4.7版本和oracle DB
这里有一个例子供参考:
private List<Post> posts;
<resultMap id="blogResult" type="Blog">
<collection property="posts" javaType="ArrayList" column="id"
ofType="Post" select="selectPostsForBlog"/>
</resultMap>
<select id="selectBlog" resultMap="blogResult">
SELECT * FROM BLOG WHERE ID = #{id}
</select>
<select id="selectPostsForBlog" resultType="Post">
SELECT * FROM POST WHERE BLOG_ID = #{id}
</select>
或
<select id="selectBlog" resultMap="blogResult">
select
B.id as blog_id,
B.title as blog_title,
B.author_id as blog_author_id,
P.id as post_id,
P.subject as post_subject,
P.body as post_body,
from Blog B
left outer join Post P on B.id = P.blog_id
where B.id = #{id}
</select>
<resultMap id="blogResult" type="Blog">
<id property="id" column="blog_id" />
<result property="title" column="blog_title"/>
<collection property="posts" ofType="Post">
<id property="id" column="post_id"/>
<result property="subject" column="post_subject"/>
<result property="body" column="post_body"/>
</collection>
</resultMap>
嵌套selectlike子查询是否还有N+1个问题?
对于哪一个在特定环境或条件下表现更好,您有什么建议或经验吗?非常感谢:).
首先是一点术语说明。 SQL中的子查询是查询的一部分,它本身就是一个查询,例如:
SELECT ProductName
FROM Product
WHERE Id IN (SELECT ProductId
FROM OrderItem
WHERE Quantity > 100)
在这种情况下,以下查询是子查询:
SELECT ProductId
FROM OrderItem
WHERE Quantity > 100
所以你在这里使用术语 "subquery" 不正确。在 mybatis 文档中使用术语 嵌套 select。
在mybatis中获取关联entities/collections有两种方式。这是 documentation 的相关部分:
Nested Select: By executing another mapped SQL statement that returns the complex type desired. Nested Results: By using nested result mappings to deal with repeating subsets of joined results.
当使用嵌套 select 时,mybatis 首先执行主查询(在你的情况下 selectBlog
),然后对每条记录执行另一个 select(因此名称 nested select
) 以获取关联的 Post
个实体。
当使用Nested results
时,只执行一个查询,但它已经加入了关联数据。所以mybatis map结果到object结构
在您的示例中返回单个 Blog
实体,因此当使用 nested select
时会执行两个查询,但在一般情况下(如果您将获得 Blog
的列表)你会遇到 N+1
问题。
现在让我们来处理性能问题。以下所有内容均假设查询已调整(因为没有丢失索引),您正在使用连接池,数据库已并置,基本上来说您的系统在所有其他方面都已调整。
谈到性能,没有唯一的正确答案,您的里程数可能会有所不同。您始终需要在您的设置中测试您的特定工作流程。考虑到影响性能的因素有很多,比如数据分布(想想 max/min/arg post 每个博客都有)、数据库中记录的大小(想想博客中数据字段的数量和大小以及 post)、数据库参数(如磁盘类型和速度、可用于数据集缓存的内存量等)可能没有单一的答案,只有随后的一些一般观察结果。
但是如果我们查看性能范围两端的案例,我们可以理解性能差异。希望看到 nested select
明显优于 join
的情况,反之亦然。
对于 collection 在大多数情况下获取连接应该更好,因为执行 N+1
请求计数的网络延迟。
nested select
可能更好的一种情况是 one-to-many 关联,当主 table 中的记录引用其他一些 table 和其他 one-to-many 的基数时=87=] 不大,而另一个 table 中的记录大小很大。
例如,让我们考虑 Blog
有一个 category
属性 引用 categories
table 并且它可能具有以下值之一 Science, Fashion, News
.让我们想象一下博客列表是 select 由博客标题中的关键字等过滤器编辑的。如果结果包含比方说 500 个项目,那么大多数相关类别将是重复的。
如果我们 select 他们加入结果集中的每条记录将包含 Category
数据字段(提醒一下,其中大部分都是重复的,我们在 Category
记录).
如果我们select他们使用嵌套select,我们会为每条记录做查询以通过类别ID获取类别,这里mybatis session缓存开始发挥作用。在 SqlSession
期间,每次 mybatis 执行查询时,它会将其结果存储在 session 缓存中,因此它不会对数据库执行重复请求,而是从缓存中获取它们。这意味着在 mybatis 通过 id 为第一条记录检索到某个类别后,它将对其处理的记录集中的所有其他记录重用它。
在上面的示例中,我们将对数据库执行最多 4 个请求,但通过网络传递的数据量减少可能会增加执行 4 个请求的需求。