什么是嵌套查詢和嵌套結果
嵌套查詢 是指通過執行另外一條 SQL 映射語句來返回預期的復雜類型;
嵌套結果 是使用嵌套結果映射來處理重復的聯合結果的子集。
開發人員可以使用上述任意一種方式實現對關聯關系的加載。
區別
嵌套查詢 | 嵌套結果 |
---|---|
嵌套查詢是在查詢 SQL 后再進行一個(子)查詢 | 嵌套結果是一個多表查詢的 SQL 語句 |
會執行多條 SQL 語句 | 只有一條復雜的 SQL 語句(多表連接) |
SQL語句編寫較為簡單 | SQL語句編寫較為復雜 |
以下給出簡單代碼比較二則區別:
<!-- 嵌套查詢:通過執行另外一條SQL映射語句來返回預期的特殊類型 -->
<resultMap id="BaseResultMap" type="com.eucheng.eusys.eusyspersonnel.domain.Depts">
<id column="id" jdbcType="INTEGER" property="id"/>
<result column="name" jdbcType="VARCHAR" property="name"/>
<result column="parent_id" jdbcType="INTEGER" property="parentId"/>
<result column="level" jdbcType="VARCHAR" property="level"/>
<result column="remark" jdbcType="VARCHAR" property="remark"/>
</resultMap>
<resultMap id="DeptsWithChildren" extends="BaseResultMap" type="com.eucheng.eusys.eusyspersonnel.domain.Depts">
<collection property="childrens" ofType="com.eucheng.eusys.eusyspersonnel.domain.Depts"
select="getAllDepartmentsByParentId" column="id"/>
</resultMap>
<select id="getAllDepartmentsByParentId" parameterType="java.lang.Integer" resultMap="DeptsWithChildren">
select
id, `name`, parent_id, `level`, remark
from dept
where parent_id = #{parent_id,jdbcType=INTEGER}
</select>
<!-- 嵌套結果:使用嵌套結果映射來處理重復的聯合結果的子集 -->
<select id="findPersonById2" parameterType="Integer"
resultMap="IdCardWithPersonResult2">
SELECT p.*,idcard.code
from tb_person p,tb_idcard idcard
where p.card_id=idcard.id
and p.id= #{id}
</select>
<resultMap type="Person" id="IdCardWithPersonResult2">
<id property="id" column="id" />
<result property="name" column="name" />
<result property="age" column="age" />
<result property="sex" column="sex" />
<association property="card" javaType="IdCard">
<id property="id" column="card_id" />
<result property="code" column="code" />
</association>
</resultMap>
嵌套查詢的執行過程是:
==> Preparing: select id, `name`, parent_id, `level`, remark from dept where parent_id = ?
==> Parameters: -1(Integer)
====> Preparing: select id, `name`, parent_id, `level`, remark from dept where parent_id = ?
====> Parameters: 0(Integer)
======> Preparing: select id, `name`, parent_id, `level`, remark from dept where parent_id = ?
======> Parameters: 1(Integer)
========> Preparing: select id, `name`, parent_id, `level`, remark from dept where parent_id = ?
========> Parameters: 2(Integer)
<======== Total: 0
========> Preparing: select id, `name`, parent_id, `level`, remark from dept where parent_id = ?
========> Parameters: 3(Integer)
<======== Total: 0
<====== Total: 2
======> Preparing: select id, `name`, parent_id, `level`, remark from dept where parent_id = ?
======> Parameters: 4(Integer)
========> Preparing: select id, `name`, parent_id, `level`, remark from dept where parent_id = ?
========> Parameters: 5(Integer)
<======== Total: 0
========> Preparing: select id, `name`, parent_id, `level`, remark from dept where parent_id = ?
========> Parameters: 6(Integer)
<======== Total: 0
<====== Total: 2
.....以下差不多相同就不截取了
嵌套結果的執行過程是:
嘿嘿沒有不想寫,就是只有一個 SQL 語句,多表聯查的那種。看參考1人家截圖去。
嵌套查詢的弊端
嵌套查詢的N+1問題:
盡管嵌套查詢大量的簡化了存在關聯關系的查詢,但它的弊端也比較明顯:即所謂的N+1問題。關聯的嵌套查詢顯示得到一個結果集,然后根據這個結果集的每一條記錄進行關聯查詢。
現在假設嵌套查詢就一個(即resultMap 內部就一個association標簽),現查詢的結果集返回條數為N,那么關聯查詢語句將會被執行N次,加上自身返回結果集查詢1次,共需要訪問數據庫N+1次。如果N比較大的話,這樣的數據庫訪問消耗是非常大的!所以使用這種嵌套語句查詢的使用者一定要考慮慎重考慮,確保N值不會很大。
嵌套語句的查詢會導致數據庫訪問次數不定,進而有可能影響到性能。
總結
所以多表查詢還是用嵌套結果,而嵌套查詢應該用在單表,階級。比如上面的部門結構,因為不確定部門的子部門有多少層,所以沒有辦法使用嵌套結果查詢。