1. 程式人生 > >MySQL SQL 優化案例:JOIN派生表

MySQL SQL 優化案例:JOIN派生表

優化之前:
SELECT
  ap.institution_id,
  date(ra.create_time) date,
  sum(

    IF (
      ra.confirm_amount > ld.debit_amount,
      ld.debit_amount,
      ra.confirm_amount
    )
  ) return_amount,
  count(ra.confirm_amount) return_count
FROM
  t_asset_package ap
JOIN (
  SELECT
    asset_package_id,
    institution_id,
    loan_document_id,
    debit_amount
  FROM
    t_loan_details
  WHERE
    is_all_paid = 1
  OR principal_paid = 1
) ld ON ap.asset_package_id = ld.asset_package_id
JOIN (
  SELECT
    loan_document_id,
    sum(confirm_amount) confirm_amount,
    create_time
  FROM
    t_return_application
  GROUP BY
    loan_document_id
) ra ON ld.loan_document_id = ra.loan_document_id
WHERE
  ap.institution_id = 'C0000012413'
AND ap.delete_flag = 0
GROUP BY
  date(ra.create_time)
ORDER BY
  date;

執行計劃:

+----+-------------+----------------------+--------+-----------------------------------------+--------------------------------------+---------+---------------------+--------+---------------------------------+
| id | select_type | table                | type   | possible_keys                           | key                                  | key_len | ref                 | rows   | Extra                           |
+----+-------------+----------------------+--------+-----------------------------------------+--------------------------------------+---------+---------------------+--------+---------------------------------+
|  1 | PRIMARY     | <derived3>           | ALL    | NULL                                    | NULL                                 | NULL    | NULL                |  89435 | Using temporary; Using filesort |
|  1 | PRIMARY     | <derived2>           | ALL    | NULL                                    | NULL                                 | NULL    | NULL                |  88516 | Using where; Using join buffer  |
|  1 | PRIMARY     | ap                   | eq_ref | PRIMARY,FK_ASSET_PACKAGE_CUSTOMER_1_idx | PRIMARY                              | 110     | ld.asset_package_id |      1 | Using where                     |
|  3 | DERIVED     | t_return_application | index  | NULL                                    | FK_RETURN_APPLICATION_DOCUMENT_1_idx | 111     | NULL                | 203837 |                                 |
|  2 | DERIVED     | t_loan_details       | ALL    | NULL                                    | NULL                                 | NULL    | NULL                |  99370 | Using where                     |
+----+-------------+----------------------+--------+-----------------------------------------+--------------------------------------+---------+---------------------+--------+---------------------------------+
需要執行21分鐘 優化思路:之前的SQL連線的是派生表,並不能有效使用到索引,導致這一寫法的直接原因是程式設計師的慣性思維,總以為先把要join的內容通過過濾、分組、聚合限定在一個小的範圍內之後再join效率較高且更符合慣常的思維模式。殊不知MySQL這麼做會導致很差的效能。要做的優化就是先直接join這樣可以利用到join欄位上的索引,之後再進行過濾、分組 、聚合。 優化後:
SELECT
  alr.institution_id,
  alr.date,
  SUM(

    IF (
      alr.confirm_amount > alr.debit_amount,
      alr.debit_amount,
      alr.confirm_amount
    )
  ) return_amount,
  count(alr.confirm_amount) return_count
FROM
  (
    SELECT
      ap.institution_id institution_id,
      DATE(ra.create_time) date,
      SUM(ra.confirm_amount) confirm_amount,
      ld.debit_amount debit_amount
    FROM
      t_asset_package ap
    JOIN t_loan_details ld ON ap.asset_package_id = ld.asset_package_id
    AND (
      ld.is_all_paid = 1
      OR ld.principal_paid = 1
    )
    JOIN t_return_application ra ON ld.loan_document_id = ra.loan_document_id
    WHERE
      ap.institution_id = 'C0000012413'
    AND ap.delete_flag = 0
    GROUP BY
      ra.loan_document_id
  ) alr
GROUP BY
  alr.date

執行計劃:

+----+-------------+------------+------+-----------------------------------------------------------+-----------------------------------------+---------+------------------------------+------+----------------------------------------------+
| id | select_type | table      | type | possible_keys                                             | key                                     | key_len | ref                          | rows | Extra                                        |
+----+-------------+------------+------+-----------------------------------------------------------+-----------------------------------------+---------+------------------------------+------+----------------------------------------------+
|  1 | PRIMARY     | <derived2> | ALL  | NULL                                                      | NULL                                    | NULL    | NULL                         |    2 | Using temporary; Using filesort              |
|  2 | DERIVED     | ap         | ref  | PRIMARY,FK_ASSET_PACKAGE_CUSTOMER_1_idx                   | FK_ASSET_PACKAGE_CUSTOMER_1_idx         | 63      |                              |    3 | Using where; Using temporary; Using filesort |
|  2 | DERIVED     | ld         | ref  | IDX_LOAN_DOCUMENT,FK_LOAN_FEE_DETAILS_ASSET_PACKAGE_1_idx | FK_LOAN_FEE_DETAILS_ASSET_PACKAGE_1_idx | 111     | dcf_loan.ap.asset_package_id |    1 | Using where                                  |
|  2 | DERIVED     | ra         | ref  | FK_RETURN_APPLICATION_DOCUMENT_1_idx                      | FK_RETURN_APPLICATION_DOCUMENT_1_idx    | 111     | dcf_loan.ld.loan_document_id |    1 | Using where                                  |
+----+-------------+------------+------+-----------------------------------------------------------+-----------------------------------------+---------+------------------------------+------+----------------------------------------------+
只需執行0.01秒