FIND_IN_SET性能优化之列转行

FIND_IN_SET 性能优化

select v_data.*, GROUP_CONCAT(t_fa.Staff_Name) Staff_Name
  from (select REC.Riqi_Date,
               REC.Vehicle_Id,
               t_vc.Vehicle_No,
               REC.DeliveryLoading_Hdr_Id,
               t_hd.DeliveryLoading_No,
               REC.Operate_staff,
               REC.Cart_check_State,
               (select a.Value_Desc
                  from Fd_Field_Dtl a
                 where a.Field_Name = 'Cart_check_State'
                   and a.Value_Data = REC.Cart_check_State) Cart_check_StateName,
               REC.ElectricalEquipment_State,
               REC.Chassis_State,
               REC.Engine_state,
               REC.Exterior_State,
               REC.Created_Time,
               REC.Submit_Time,
               REC.Repair_Item
          from Rec_a           REC,
               Fd_Vb               t_vc,
               Bill_Dc t_hd
         where REC.Vehicle_Id = t_vc.Vehicle_Id
           and t_hd.Operator_Id = '174660684877367'
           and REC.DeliveryLoading_Hdr_Id = t_hd.DeliveryLoading_Hdr_Id
           and REC.Cart_check_State < 4
         order by REC.Riqi_Date desc) v_data
  LEFT JOIN Fd_Staff t_fa
    on FIND_IN_SET(t_fa.Staff_Id, v_data.Operate_staff) > 0
 GROUP BY v_data.DeliveryLoading_Hdr_Id
 order by v_data.Riqi_Date;

查看执行计划

+----+--------------------+------------+--------+-----------------------------------------------------------+---------------------------+---------+--------------------------------+-------+-----------------------------------------------------------------+
| id | select_type        | table      | type   | possible_keys                                             | key                       | key_len | ref                            | rows  | Extra                                                           |
+----+--------------------+------------+--------+-----------------------------------------------------------+---------------------------+---------+--------------------------------+-------+-----------------------------------------------------------------+
|  1 | PRIMARY            |  | ALL    | NULL                                                      | NULL                      | NULL    | NULL                           |   741 | Using temporary; Using filesort                                 |
|  1 | PRIMARY            | t_fa       | index  | NULL                                                      | Staff_Name                | 402     | NULL                           | 40141 | Using where; Using index; Using join buffer (Block Nested Loop) |
|  2 | DERIVED            | REC        | ALL    | PRIMARY,DeliveryLoading_Hdr_Id,Cart_check_State           | NULL                      | NULL    | NULL                           |   741 | Using where; Using filesort                                     |
|  2 | DERIVED            | t_vc       | eq_ref | PRIMARY,PK_Vehicle_Id                                     | PRIMARY                   | 128     | TMP.REC.Vehicle_Id             |     1 | NULL                                                            |
|  2 | DERIVED            | t_hd       | eq_ref | Pk_DeliveryLoading_Hdr_Id,Operator_Id,Bill_Hdr_Id_Vehicle | Pk_DeliveryLoading_Hdr_Id | 128     | TMP.REC.DeliveryLoading_Hdr_Id |     1 | Using where                                                     |
|  3 | DEPENDENT SUBQUERY | a          | eq_ref | PRIMARY,UK_NAME_DATA                                      | UK_NAME_DATA              | 340     | const,TMP.REC.Cart_check_State |     1 | Using index condition                                           |
+----+--------------------+------------+--------+-----------------------------------------------------------+---------------------------+---------+--------------------------------+-------+-----------------------------------------------------------------+

t_fa 表使用Staff_Name索引,消耗物理行数40141 ,整个SQL跑完要8秒。

利用”列转行”将FIND_IN_SET 转换成

FIND_IN_SET(t_fa.Staff_Id, v_data.Operate_staff) 改换为

   t_fa.Staff_Id in   (select replace(substring(substring_index(v_data.Operate_staff,
                                                 ',',
                                                 s),
                                 char_length(substring_index(v_data.Operate_staff,
                                                             ',',
                                                             s - 1)) + 1),
                       ',',
                       '') as f
          from t_seq  where s <= length(v_data.Operate_staff) - length(replace(v_data.Operate_staff, ',', '') )+1 )

其中t_seq如下
select * from t_seq ;
+——+
| s |
+——+
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
| 6 |
| 7 |
| 8 |
| 9 |
| 10 |
+——+

转换之后整个SQL如下:

select v_data.*, GROUP_CONCAT(t_fa.Staff_Name) Staff_Name
  from (select REC.Riqi_Date,
               REC.Vehicle_Id,
               t_vc.Vehicle_No,
               REC.DeliveryLoading_Hdr_Id,
               t_hd.DeliveryLoading_No,
               REC.Operate_staff,
               REC.Cart_check_State,
               (select a.Value_Desc
                  from Fd_Field_Dtl a
                 where a.Field_Name = 'Cart_check_State'
                   and a.Value_Data = REC.Cart_check_State) Cart_check_StateName,
               REC.ElectricalEquipment_State,
               REC.Chassis_State,
               REC.Engine_state,
               REC.Exterior_State,
               REC.Created_Time,
               REC.Submit_Time,
               REC.Repair_Item
          from Rec_a           REC,
               Fd_Vb               t_vc,
               Bill_Dc t_hd
         where REC.Vehicle_Id = t_vc.Vehicle_Id
           and t_hd.Operator_Id = '174660684877367'
           and REC.DeliveryLoading_Hdr_Id = t_hd.DeliveryLoading_Hdr_Id
           and REC.Cart_check_State < 4
         order by REC.Riqi_Date desc) v_data
  LEFT JOIN Fd_Staff t_fa
    on t_fa.Staff_Id in
       (select replace(substring(substring_index(v_data.Operate_staff,
                                                 ',',
                                                 s),
                                 char_length(substring_index(v_data.Operate_staff,
                                                             ',',
                                                             s - 1)) + 1),
                       ',',
                       '') as f
          from t_seq  where s <= length(v_data.Operate_staff) - length(replace(v_data.Operate_staff, ',', '') )+1 )
 GROUP BY v_data.DeliveryLoading_Hdr_Id
 order by v_data.Riqi_Date;

查看执行计划:

+----+--------------------+------------+--------+-----------------------------------------------------------+---------------------------+---------+--------------------------------+------+--------------------------------------------------+
| id | select_type        | table      | type   | possible_keys                                             | key                       | key_len | ref                            | rows | Extra                                            |
+----+--------------------+------------+--------+-----------------------------------------------------------+---------------------------+---------+--------------------------------+------+--------------------------------------------------+
|  1 | PRIMARY            |  | ALL    | NULL                                                      | NULL                      | NULL    | NULL                           |  748 | Using temporary; Using filesort; Start temporary |
|  1 | PRIMARY            | t_seq      | ALL    | NULL                                                      | NULL                      | NULL    | NULL                           |   10 | Using where                                      |
|  1 | PRIMARY            | t_fa       | eq_ref | PRIMARY,Staff_Id                                          | PRIMARY                   | 128     | func                           |    1 | Using where; End temporary                       |
|  2 | DERIVED            | REC        | ALL    | PRIMARY,DeliveryLoading_Hdr_Id,Cart_check_State           | NULL                      | NULL    | NULL                           |  748 | Using where; Using filesort                      |
|  2 | DERIVED            | t_vc       | eq_ref | PRIMARY,PK_Vehicle_Id                                     | PRIMARY                   | 128     | TMP.REC.Vehicle_Id             |    1 | NULL                                             |
|  2 | DERIVED            | t_hd       | eq_ref | Pk_DeliveryLoading_Hdr_Id,Operator_Id,Bill_Hdr_Id_Vehicle | Pk_DeliveryLoading_Hdr_Id | 128     | TMP.REC.DeliveryLoading_Hdr_Id |    1 | Using where                                      |
|  3 | DEPENDENT SUBQUERY | a          | eq_ref | PRIMARY,UK_NAME_DATA                                      | UK_NAME_DATA              | 340     | const,TMP.REC.Cart_check_State |    1 | Using index condition                            |
+----+--------------------+------------+--------+-----------------------------------------------------------+---------------------------+---------+--------------------------------+------+--------------------------------------------------+

t_fa 使primary索引,消耗物理行数1,整个sql跑完只要0.04秒。

你可能感兴趣的:(mysql,调优)