一次Sql優化的體驗

今天遇到一個SQL優化的問題,記錄下來

測試部門反映,有個功能的查詢很緩慢,需要支持排查下

首先描述下具體的問題

數據庫中一張表的大概有700多條記錄,業務需要模擬一個類似屬性樹形的數據結構,需要查詢所有父類的列表數據,查詢出來符合記錄的大概有400多條,目前測試點擊查詢,所需要的時間大概在4s多,這個效率實在太慢了;

下面是SQL的內容

    SELECT
      (SELECT
        MAX(f.url)
      FROM
        order_definnition o
         JOIN order_def_form_relation d
          ON o.id = d.pid
          AND d.is_interflow = 1
          AND o.is_deleted = 0
          AND d.is_deleted = 0
         JOIN form f
          ON f.id = d.form_id
          AND f.is_deleted = 0
      WHERE o.resource_code = t.from_oddf_class_no) AS url,
      (SELECT
        MAX(f.url)
      FROM
        order_definnition o
         JOIN order_def_form_relation d
          ON o.id = d.pid
          AND d.is_audit = 1
          AND o.is_deleted = 0
          AND d.is_deleted = 0
         JOIN form f
          ON f.id = d.form_id
          AND f.is_deleted = 0
      WHERE o.resource_code = t.from_oddf_class_no) AS source_url,
      id
    FROM
      unicom_send_recv_order t
    WHERE is_deleted = 0
      AND t.id IN
      (SELECT
        (SELECT
          b.id
        FROM
          unicom_send_recv_order b
        WHERE b.is_deleted = 0
          AND b.unicom_first_id = a.unicom_first_id
          AND (
            b.data_direction = 0
            OR (
              b.data_direction = 1
              AND (
                b.order_status = '1001516'
                OR b.order_status = '1001515'
              )
            )
            OR b.is_start_line = 1
          )
        ORDER BY b.send_recv_count DESC
        LIMIT 1)
      FROM
        unicom_send_recv_order a
      WHERE a.is_deleted = 0
      GROUP BY a.unicom_first_id)
    ORDER BY t.created_time DESC

這個sql的邏輯,在滿足一定的條件下,選擇send_recv_count最大的那條記錄的id來展示。

添加索引

在不影響業務的條件下,我們通過添加索引來試試,查看錶中的關聯字段,我們需要對如下的字段添加索引

    ALTER TABLE `sceo`.`unicom_send_recv_order`   
      ADD  INDEX `index_unicom_first_id` (`unicom_first_id`),
      ADD  INDEX `index_from_oddf_class_no` (`from_oddf_class_no`),
      ADD  INDEX `index_send_recv_count` (`send_recv_count`);
    ALTER TABLE `sceo`.`order_def_form_relation`   
      ADD  INDEX `index_pid` (`pid`),
      ADD  INDEX `index_form_id` (`form_id`);

再次執行該上面的sql語句,發現查詢的效率變快了了,耗時2700+ms數,這個時間還是滿足不了業務的需要

重構sql

分析上述的sql,發現在子查詢中通過排序來獲取send_recv_count最大的記錄,然後再分組查詢,這個是主要導致查詢效率緩慢的原因,我們可以改寫sql語句來減少分組和排序

我們利用變量來爲排序標記,然後獲取變量爲1的記錄,利用這種方式來避免排序分組, 重構的sql如下:

    SELECT
      (SELECT
        MAX(f.url)
      FROM
        order_definnition o
         JOIN order_def_form_relation d
          ON o.id = d.pid
          AND d.is_interflow = 1
          AND o.is_deleted = 0
          AND d.is_deleted = 0
         JOIN form f
          ON f.id = d.form_id
          AND f.is_deleted = 0
      WHERE o.resource_code = t.from_oddf_class_no) AS url,
      (SELECT
        MAX(f.url)
      FROM
        order_definnition o
         JOIN order_def_form_relation d
          ON o.id = d.pid
          AND d.is_audit = 1
          AND o.is_deleted = 0
          AND d.is_deleted = 0
         JOIN form f
          ON f.id = d.form_id
          AND f.is_deleted = 0
      WHERE o.resource_code = t.from_oddf_class_no) AS source_url, id
    FROM
      unicom_send_recv_order t
    WHERE is_deleted = 0
       AND EXISTS
      (SELECT tt.id from (SELECT
    	b.id,
    	b.unicom_first_id,
    	send_recv_count,
    IF (
    	@pre_course_id = b.unicom_first_id,
    	@cur_rank := @cur_rank + 1,
    	@cur_rank := 1
    ) ranking,
     @pre_course_id := b.unicom_first_id
    FROM
    	unicom_send_recv_order b,
    	(SELECT
    			@cur_rank := 0,
    			@pre_course_id := NULL
    	) r
    where b.is_deleted = 0 
          AND (b.data_direction = 0
           OR (b.data_direction = 1
              AND (b.order_status = '1001516'
                OR b.order_status = '1001515'))
            OR b.is_start_line = 1)
    ORDER BY
    	unicom_first_id,
    	send_recv_count DESC) tt where tt.ranking = 1
    	AND tt.id = t.id)
    ORDER BY t.created_time DESC

在重構後的sql中,可以看到我們排序之後的記錄添加一個序列,然後獲取序列的第一條來作爲我們現實的記錄,然後將in改爲exists,這樣優化後的查詢就變得效率很高了,經過測試,耗時降到了200ms,這個速度暫時是可以接受的了

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