7 sql執行過程 3

2021-09-26 01:43:46 字數 3188 閱讀 3756

多結果集

下面的例子來自

有兩條sql語句

select * from blog where id = #

select * from author where id = #

有下xml配置

)}

可以看到,假設不支援多結果集,那麼對於blog關聯了author的情況就需要多條sql語句來執行了,容易產生n+1的問題

現在的jdbc驅動支援多資料集的返回了,所以只要執行一次即可

那麼拿到的第乙個resultset就不包含author的資訊,在mybatis中是先通過乙個pendingrelation來記錄父屬性對映,這裡的父屬性對映從這裡的配置來看,它就是author屬性

mybatis首先建立乙個pendingrelation,它有兩個屬性

private static class pendingrelation
這個author需要迴圈到下乙個resultset時才能真正獲取都值

下面繼續嵌入resultmap的分析,對於嵌入的,通常我們將使用多表關聯的方式去執行sql

//defaultresultcontext 維護這生成的返回物件

final defaultresultcontextresultcontext = new defaultresultcontext();

//跳過rowbounds.getoffset

skiprows(rsw.getresultset(), rowbounds);

object rowvalue = previousrowvalue;

//shouldprocessmorerows 表示是否繼續 受rowbounds.getlimit的限制

while (shouldprocessmorerows(resultcontext, rowbounds) && rsw.getresultset().next())

//建立值

//(*1*)

rowvalue = getrowvalue(rsw, discriminatedresultmap, rowkey, null, partialobject);

} else }}

previousrowvalue = null;

} else if (rowvalue != null)

} //(*1*)

final string resultmapid = resultmap.getid();

//分組物件

object resultobject = partialobject;

if (resultobject != null) else

//應用屬性對映

//儲存ancestorobjects.put(resultmapid, resultobject);

putancestor(resultobject, resultmapid, columnprefix);

//獲取嵌入的resultmap,然後建立其物件,最後設定到父物件中(metaobject)

//(*1*)

//移除父物件

ancestorobjects.remove(resultmapid);

foundvalues = lazyloader.size() > 0 || foundvalues;

resultobject = foundvalues ? resultobject : null;

}if (combinedkey != cachekey.null_cache_key)

}return resultobject;

}//(*1*)

boolean foundvalues = false;

//獲取嵌入的nestedresultmapid

//如果存在嵌入的resultmapid並且沒有指定resultset(有表示是多結果集的操作,不屬於嵌入resultmap)

try

} else }}

} catch (sqlexception e) }}

return foundvalues;

} 所以mybatis,對於嵌入的resultmap是通過快取key來分組的,設定嵌入的值,如果嵌入的值還有嵌入的值,可以繼續遞迴獲取值,繼續嵌入,還會快取resultmapid -> 物件的關係,因為有些物件之間會相互引用,那就沒有必要重新建立了。

比如我們有blog物件,它內部又乙個屬性autors,它是乙個list,那麼對於join查詢,我們肯定要根據resultset返回的結果進行分組,那麼分組的key是怎麼建立的呢?首先對於第一層物件的cachekey建立**如下:

final cachekey cachekey = new cachekey();

//首先resultmapid,表示這個結果集所屬resultmap

cachekey.update(resultmap.getid());

//如果沒有主鍵對映

//並且對映的屬性是map的話,那麼將所有的欄位名和對應的字段值設定為cachekey的一部分

if (map.class.isassignablefrom(resultmap.gettype())) else

} else

//如果沒有對映任何字段,返回cachekey.null_cache_key

//按道理,如果存在乙個字段對映都會update 2次,比如只有乙個主鍵的情況下就是update 2次

if (cachekey.getupdatecount() < 2)

return cachekey;

} 對於嵌入屬性的嵌入屬性,依次通過以下方法設定cachekey

private cachekey org.apache.ibatis.executor.resultset.defaultresultsethandler#combinekeys(cachekey rowkey, cachekey parentrowkey)  catch (clonenotsupportedexception e) 

combinedkey.update(parentrowkey);

return combinedkey;

}return cachekey.null_cache_key;

}

非常簡單,就是將父cachekey作為自己cachekey的一部分,保證唯一性。

7 SQL優化技術

7.1 改變訪問結構 7.2 修改sql語句 7.3 提示hint 提示的分類 初始化引數提示 all rows,cursor sharing extract,dynamic sampling,first rows,gather plan statistics 查詢轉化提示 no eliminate...

資料庫優化專題 7 SQL語句優化

資料庫優化專題 1 表的主鍵用數字還是uuid 資料庫優化專題 2 邏輯刪除還是物理刪除 資料庫優化專題 3 千萬記錄如何快速分頁 資料庫優化專題 4 讀多寫少和讀多寫多 資料庫優化專題 5 刪改資料如何避免鎖表 資料庫優化專題 6 如何避免偷換交易中的商品資訊 資料庫優化專題 7 sql語句優化 ...

sql執行過程

程式中寫的一條sql傳送到伺服器端 查詢此條sql是否存在執行計畫 如果存在則直接呼叫已經編譯好的執行計畫 否則進入下一步。如果sql計畫快取中沒有對應的執行計畫,則進行語法校驗 檢視是否存在語法錯誤 如果語法沒有錯誤則進行語義校驗,例如,表名,列名,儲存過程等等資料庫物件是否真正存在 如果語義沒有...