Mybatis查詢超時

問題現象

測試同學反饋,商品查詢功能,輸入字母或漢字正常,輸入數字搜索時報錯。

問題排查

初次排查

查看了一下耗時點,在mybatis執行到DruidDataSource.getConnect方法之間耗時很久(兩次,每次都差不多100s左右)。
在這裏插入圖片描述

猜測:連接池問題,全部被佔用,在等待連接?
查看了下getConnection代碼, 裏面纔開始獲取連接,說明這個中間過程還沒有進行連接獲取

public DruidPooledConnection getConnection() throws SQLException {
    return getConnection(maxWait);
}

這個功能,在其他環境驗證的時候正常,上線很久了,也沒有暴露過問題。查看了這個接口對應的請求,在那個點附近的幾十、百多秒,之前、之後的都在1s內。
在這裏插入圖片描述

當時查看部署服務器,那個時間段CPU耗時較高。環境之前出現過不穩定的情況,當時以爲環境問題,適當加大了接口超時時間。
在這裏插入圖片描述

問題再現

第二天,測試反饋又重現了。一次可以是湊巧,兩次可能性很低。
看了下請求數據,超時請求,輸入的搜索關鍵字是"2"。關鍵字會去模糊匹配商品名稱和條碼。匹配到很多商品?
查看了下數據庫裏面的商品,搜索條件下模糊匹配到幾W條。pinpoint裏面參數也印證了。
在這裏插入圖片描述

對比分析了下之前輸入中文或字母搜索的,匹配的商品數量很少。
由於是測試環境,之前批量造數據的時候,商品名稱不規範,數字"2"匹配到了很多。

至此找到了根本原因,如下:
我們的商品條碼和商品名稱是存放在兩張表的。查看代碼實現,是先去條碼錶模糊匹配,找到一批商品ukid,然後在作爲入參,去商品表裏面做分頁查詢,計算總量等。
商品數據量很大,mybatis做動態sql拼接時耗時很久。 從mybatis開始執行,到getConnection,中間是完成SQL組裝。

商品表查詢,xml配置

<select id="selectRsDefineds" parameterType="java.lang.Long" resultMap="BaseResultMap">
  select
  <include refid="Base_Column_List" />
  from rs_defined r
  where
  defined_ukid IS NOT NULL
  <if test="buIds != null">
    and definer_id in
    <foreach close=")" collection="buIds" item="ownerUkid" open="(" separator=",">
      #{ownerUkid}
    </foreach>
  </if>
  <if test="definedName != null">
    and
    (
    defined_name LIKE #{definedName}
    <if test="inDefinedUkidList != null">
      or defined_ukid in
      <foreach close=")" collection="inDefinedUkidList" item="definedUkid" open="(" separator=",">
        #{definedUkid}
      </foreach>
    </if>
    )
  </if>
  <if test="statusList != null">
    and status in
    <foreach close=")" collection="statusList" item="status" open="(" separator=",">
      #{status}
    </foreach>
  </if>
  <if test="statusList == null">
    and status = 1
  </if>
  <if test="typeList != null">
    and defined_type in
    <foreach close=")" collection="typeList" item="type" open="(" separator=",">
      #{type}
    </foreach>
  </if>
  <if test="debarUkids != null">
    and defined_ukid NOT IN
    <foreach close=")" collection="debarUkids" item="debarDefinedUkid" open="(" separator=",">
      #{debarDefinedUkid}
    </foreach>
  </if>
  <if test="sku != null">
    and sku = #{sku,jdbcType=BIGINT}
  </if>
  <if test="sort != null">
    ORDER BY ${sort}
  </if>
  <if test="limit != null">
    <if test="offset != null">
      limit ${offset}, ${limit}
    </if>
    <if test="offset == null">
      limit ${limit}
    </if>
  </if>
</select>

解決方案

通過elasticSearch查詢

直接把所有商品數據同步到es,通過es做搜索。
自測耗時500ms左右。 (總量:28w+,匹配到的數據量:15w+,虛擬機)

公司已有es環境,es本身用於搜索,對大數據量篩選過濾、匹配度等支持更好。而且調整成本不高。

其他方案

  • 自身在程序中做SQL拼接,不要用mybatis的。 針對這種特定場景,沒必要所有的均如此
  • 表結構設計調整,條碼、名稱 聚合到一張表中進行搜索匹配

補充說明

mybatis做動態sql拼接,很久以前碰到過一次棧溢出的。當時查詢到SQL拼接使用的visitor模式,構造了比較複雜的語法樹。
本次這塊沒有去往下分析。有大神歡迎賜教,或者有資料分享下,謝

之前棧溢出的記錄
https://blog.csdn.net/LG772EF/article/details/58636910

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章