java-mysql優化歷程

起因

web運行頁面加載速度突然變慢,從5秒左右變爲2~3分鐘。

查找問題源頭:

1:代碼問題:

因爲業務邏輯複雜,運行兩段sql進行數據查詢,根據第一段sql查出來的數id在第二段sql裏進行in查詢,但由於第一段sql查出的數據量大概有6W+,所以在拼接sql中字符串長度過長導致報錯GC。

2:數據庫問題:

因爲業務邏輯變更,導致sql查詢的其中一張表,從1~2w條數據四五天內增加至150W+,導致單表查詢運行速度超過5s,關聯查詢至少要20s左右。

解決:

1:修改代碼邏輯,通過獲取小數據量的值對大的sql進行關聯查詢,減少java內存消耗。

其中有一段業務邏輯是要獲取一棵樹上根據樹的多個節點,獲取多個節點下的所有子節點,開始的想法是,根據java代碼來實現,實現方式是:

  • 獲取某個父節點下面的所有子節點
  /* 獲取某個父節點下面的所有子節點
     * @param menuList
     * @param pid
     * @return
     */
    static List<String> childMenu = new ArrayList<>();
    public static List<String> treeMenuList(List<Map<String, Object>> menuList, String pid) {
        for (Map<String, Object> mu : menuList) {
            //遍歷出父id等於參數的id,add進子節點集合
            if (pid.equals(String.valueOf(mu.get("parentid")))) {
                //遞歸遍歷下一級
                treeMenuList(menuList, String.valueOf(mu.get("id")));
                childMenu.add(String.valueOf(mu.get("id")));
            }
        }
        return childMenu;
    }

但是這種方式仍然會使優化過mysql後的加載速度達到7~8秒,由於時間問題沒有去管爲什麼會慢,但猜測是因爲傳入的List集合過大。
思考另外一種方案用mysql函數去處理這段邏輯,在一片文章中找到很好的例子:

SELECT * FROM person WHERE department IN
(SELECT department_id FROM department WHERE department_id = 20006
UNION
(SELECT department_id FROM
  (SELECT  * FROM department ORDER BY parent_id,department_id) depart_sorted,
  (SELECT @pv := 20006) initialisation
WHERE find_in_set(parent_id,@pv)
AND length(@pv := concat(@pv,',',department_id))));

生產庫中測試運行速度秒級,已達標。

2:優化sql,創建索引

由於是數據量突然增加的問題導致的,首先想到的就是創建索引。
但是沒想到,創建索引的時間超出我的想象,分別用了腳本,navicat,倒庫等多中方式創建都不成功,開始想到的是因爲數據量太大,在等待一個小時後發現還沒有成功,知道事情沒有這麼簡單,開始尋找出路。。。。。
是否有某個查詢把表造成死鎖;查詢:

select trx_state, trx_started, trx_mysql_thread_id, trx_query from information_schema.innodb_trx;

查詢後果然發現了一條有關建索引表的sql存在死鎖,果斷kill。

至此頁面加載的速度已經從23分鐘優化至23秒(其中包括一些sql語句的優化未寫出);

才疏學淺,不喜勿噴。

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