优化多个连接到同一个表MySQL

时间:2015-10-25 17:14:13

标签: mysql join

我有一个查询,它连接在同一个表(user_status)中多次,以便回退不同的状态信息。此查询的总体目标是将其转换为视图。我相信这些连接会导致查询运行时间延迟,从而导致查询挂起。我试图尽可能地优化查询,但不知道除了拥有所有这些连接之外的其他方式。连接是左连接,因为我想看到返回null值。 where子句过滤器用于返回最多370天前的时间轴数据。我将在下面粘贴我的查询;任何建议都会非常感激:

SELECT 
    c.id AS customer_id,
    c.priority AS priority,
    c.create_date AS create_date,
    u.login AS login,
    c.due_date AS due_date,
    ts.user_status AS status,
    cts.status AS current_status,
    cts.id AS status_id,
    w.name AS workflow_name,
    c.summary AS summary,
    cfi.added_by AS acknowledged_by,
    CONCAT(dispatch_user.first_name,' ',dispatch_user.last_name) AS dispatch_user, 
    CONCAT(dispatched_user.first_name,' ',dispatched_user.last_name) AS acknowledged,
    CONCAT(last_update_by.first_name,' ',last_update_by.last_name) AS manager_last_updated_by,
    c.updated_date AS updated_date,
    CONCAT(u.first_name,' ',u.last_name) AS last_updated_by,
    ts_new.status_date AS new_dt,
    ts_initial.status_date AS initial_dt,
    ts_assigned.status_date AS assigned_dt,
    ts_investigating.status_date AS investigating_dt,
    ts_resolved.status_date AS resolved_dt,
    ts_pending_closure.status_date AS pending_closure_dt,
    ts_closed.status_date AS closed_dt,
    IF(user_visit.status IS NOT NULL, 'Yes', 'No') AS user_visit,
    fftr.reason AS reason,
    fftr.notes AS resolution,
FROM customer c
JOIN form1 AS tcv ON (c.id = tcv.customer_id)
JOIN user_status AS cts ON (c.current_status_id = cts.id)
JOIN user AS u ON (u.id = cts.status_by_id)
LEFT JOIN user_status AS ts ON (ts.workflow_state = cts.status)
LEFT JOIN change_info AS cfi ON cfi.customer_id = c.id
LEFT JOIN user_status AS dispatch_status ON dispatch_status.customer_id = c.id AND dispatch_status.status = 'FTD'
LEFT JOIN user AS dispatch_user ON dispatch_user.id = dispatch_status.status_by_id
LEFT JOIN user_status AS assigned_ft_dis ON assigned_ft_dis.customer_id = c.id AND assigned_ft_dis.status = 'ASSIGNED - FTD'
LEFT JOIN user_status AS assigned_ft_dis_rx ON assigned_ft_dis_rx.customer_id = c.id AND assigned_ft_dis_rx.status = 'ASSIGNED - FT'
LEFT JOIN user AS dispatched_user ON dispatched_user.id = assigned_ft_dis_rx.status_by_id
LEFT JOIN user_status AS last_update_status ON last_update_status.id = c.current_status_id
LEFT JOIN user last_update_by ON last_update_by.id = last_update_status.status_by_id
LEFT JOIN user_status AS ts_new ON c.id = ts_new.customer_id AND ts_new.status LIKE 'NEW%'
LEFT JOIN user_status AS ts_initial ON c.id = ts_initial_diagnosis.customer_id AND ts_initial_diagnosis.status LIKE 'INITIAL SOLUTION%'
LEFT JOIN user_status AS ts_assigned ON c.id = ts_assigned.customer_id AND ts_assigned.status LIKE 'ASSIGNED%'
LEFT JOIN user_status AS ts_investigating ON c.id = ts_investigating.customer_id AND ts_investigating.status LIKE 'INVESTIGATING%'
LEFT JOIN user_status AS ts_resolved ON c.id = ts_resolved.customer_id AND ts_resolved.status LIKE 'RESOLVED%'
LEFT JOIN user_status AS ts_pending_closure ON c.id = ts_pending_closure.customer_id AND ts_pending_closure.status LIKE 'PENDING CLOSURE%'
LEFT JOIN user_status AS ts_closed ON c.id = ts_closed.customer_id AND ts_closed.status LIKE 'CLOSED%'
LEFT JOIN user_status AS user_visit ON c.id = user_visit.customer_id AND user_visit.status = 'RESOLVED – FT'
LEFT JOIN change AS tc_fftr ON c.id = tc_fftr.customer_id AND tc_fftr.contents LIKE 'Resolution%'
LEFT JOIN form4 AS fftr ON fftr.change_id = tc_fftr.id
WHERE
    c.create_date >= DATE_SUB(NOW(),INTERVAL 370 DAY)

1 个答案:

答案 0 :(得分:2)

首先,列出的查询不会运行,因为您没有“w”别名,并且在最后一个字段后面有一个尾随逗号。我已经(稍微)重写了可读性和彼此的关系,并改变了一些“别名”。

SELECT 
      c.id as customer_id,
      c.priority as priority,
      c.create_date as create_date,
      u.login as login,
      c.due_date as due_date,
      ts.user_status as status,
      cts.status as current_status,
      cts.id as status_id,
      w.name as workflow_name,
      c.summary as summary,
      cfi.added_by as acknowledged_by,
      concat(du.first_name,' ',du.last_name) as dispatch_user, 
      concat(disU.first_name,' ',disU.last_name) as acknowledged,
      concat(updBy.first_name,' ',updBy.last_name) as manager_last_updated_by,
      c.updated_date as updated_date,
      concat(u.first_name,' ',u.last_name) as last_updated_by,
      ts_new.status_date as new_dt,
      tsi.status_date as initial_dt,
      tsa.status_date as assigned_dt,
      tsinv.status_date as investigating_dt,
      tsres.status_date as resolved_dt,
      tspc.status_date as pending_closure_dt,
      ts_closed.status_date as closed_dt,
      IF(uv.status IS NOT NULL, 'Yes', 'No') as user_visit,
      fftr.reason as reason,
      fftr.notes as resolution
   FROM
      customer c
         join form1 tcv 
            on (c.id = tcv.customer_id)

         join user_status cts 
            on c.current_status_id = cts.id
            join user u 
               on cts.status_by_id = u.id 
            left join user_status ts 
               on cts.status = ts.workflow_state

         left join change_info cfi 
            on c.id = cfi.customer_id

         left join user_status ds 
            on c.id = ds.customer_id 
            and ds.status = 'FTD'
            left join user du 
               on ds.status_by_id = du.id

         left join user_status ftDis 
            on c.id = ftDis.customer_id 
            and ftDis.status = 'ASSIGNED - FTD'

         left join user_status rx 
            on c.id = rx.customer_id 
            and rx.status = 'ASSIGNED - FT'
            left join user disU 
               on rx.status_by_id = disU.id

         left join user_status lus 
            ON c.current_status_id = lus.id
            left join user updBy 
               on lus.status_by_id = updBy.id

         left join user_status ts_new 
            on c.id = ts_new.customer_id 
            and ts_new.status like 'NEW%'

         left join user_status tsi
            on c.id = tsi.customer_id 
            and tsi.status like 'INITIAL SOLUTION%'

         left join user_status tsa 
            on c.id = tsa.customer_id 
            and tsa.status like 'ASSIGNED%'

         left join user_status tsinv 
            on c.id = tsinv.customer_id 
            and tsinv.status like 'INVESTIGATING%'

         left join user_status tsres 
            on c.id = tsres.customer_id 
            and tsres.status like 'RESOLVED%'

         left join user_status tspc 
            on c.id = tspc.customer_id 
            and tspc.status like 'PENDING CLOSURE%'

         left join user_status ts_closed 
            on c.id = ts_closed.customer_id 
            and ts_closed.status like 'CLOSED%'

         left join user_status uv 
            on c.id = uv.customer_id 
            and uv.status = 'RESOLVED – FT'

         left join change tc_fftr 
            ON c.id = tc_fftr.customer_id 
            and tc_fftr.contents LIKE 'Resolution%'
            left join form4 fftr 
               ON tc_fftr.id = fftr.change_id 
   WHERE
      c.create_date >= DATE_SUB(NOW(),INTERVAL 370 DAY)
   GROUP BY 
      customer_id

我会确保你的桌子上有以下复合索引......

table        index
customer     (create_date, id)
form1        (customer_id)
change_info  (customer_id, added_by)
user_status  (id, status_by_id, status )
user         (id, first_name, last_name)
user_status  (customer_id, status, status_date, status_by_id )
change       (customer_id, contents, id )
form4        (change_id)

此外,您似乎甚至没有使用assigned_ft_dis(更改别名为ftDis)

然后,在...的“form1”之后的联接中。

     join user_status cts 
        on c.current_status_id = cts.id
        join user u 
           on cts.status_by_id = u.id 
        left join user_status ts 
           on cts.status = ts.workflow_state

为什么要通过别名“ts”再次基于cts.status重新加入user_status表。如果您有10k状态为“NEW”的记录,则您将连接到workflow_state的所有记录。您没有与客户ID关联的任何内容。但是因为你在连接链中是先前的,所以通过current_status_id加入(我只能GUESS是user_status表的自动增量ID)。这是一个错误吗?您是否尝试获取“workflow_state”的一些说明。我相信这一部分对你的表现有很大影响。是否有不同的TABLE(workflow_state的别名“w”)未在此处准确反映?

现在,可能会重写。对用户状态和用户表执行单个连接以确定相应的状态元素以及由谁和做什么情况/何时用于标准......类似于......我使用“US”表示User_Status别名,使用“U2”表示每个相应“用户状态”条目的通用“用户”参考。现在,注意所有情况/何时实例。由于我只加入状态,然后没有特定条件的用户表,我可以在FIELD条件级别应用条件,并且可以为null或适用,并同时获取日期和操作的对象。

SELECT 
      c.id as customer_id,
      c.priority as priority,
      c.create_date as create_date,
      u.login as login,
      c.due_date as due_date,
      ts.user_status as status,
      cts.status as current_status,
      cts.id as status_id,
      w.name as workflow_name,
      c.summary as summary,

      MAX( case when US.status = 'FTD' then US.Status_Date END ) as dispatch_date, 
      MAX( case when US.status = 'FTD' then concat(U2.first_name,' ',U2.last_name) END ) as dispatch_user, 

      MAX( case when US.status = 'ASSIGNED - FTD' then US.Status_Date END ) as assigned_date, 
      MAX( case when US.status = 'ASSIGNED - FTD' then concat(U2.first_name,' ',U2.last_name) END ) as assigned_user, 

      MAX( case when US.status = 'ASSIGNED - FT' then US.Status_Date END ) as assigned2_date, 
      MAX( case when US.status = 'ASSIGNED - FT' then concat(U2.first_name,' ',U2.last_name) END ) as assigned2_user, 

      MAX( case when US.status like 'NEW%' then US.Status_Date END ) as new_date, 
      MAX( case when US.status like 'NEW%' then concat(U2.first_name,' ',U2.last_name) END ) as new_user, 

      MAX( case when US.status like 'INITIAL SOLUTION%' then US.Status_Date END ) as solution_date, 
      MAX( case when US.status like 'INITIAL SOLUTION%' then concat(U2.first_name,' ',U2.last_name) END ) as solution_user, 

      MAX( case when US.status like 'ASSIGNED%' then US.Status_Date END ) as assigned_date, 
      MAX( case when US.status like 'ASSIGNED%' then concat(U2.first_name,' ',U2.last_name) END ) as assigned_user, 

      MAX( case when US.status like 'INVESTIGATING%' then US.Status_Date END ) as investigate_date, 
      MAX( case when US.status like 'INVESTIGATING%' then concat(U2.first_name,' ',U2.last_name) END ) as investigate_user, 

      MAX( case when US.status like 'RESOLVED%' then US.Status_Date END ) as resolved_date, 
      MAX( case when US.status like 'RESOLVED%' then concat(U2.first_name,' ',U2.last_name) END ) as resolved_user, 

      MAX( case when US.status like 'PENDING CLOSURE%' then US.Status_Date END ) as pendClose_date, 
      MAX( case when US.status like 'PENDING CLOSURE%' then concat(U2.first_name,' ',U2.last_name) END ) as pendClose_user, 

      MAX( case when US.status like 'CLOSED%' then US.Status_Date END ) as closed_date, 
      MAX( case when US.status like 'CLOSED%' then concat(U2.first_name,' ',U2.last_name) END ) as closed_user, 

      MAX( case when US.status = 'RESOLVED - FT' then US.Status_Date END ) as resolved_date, 
      MAX( case when US.status = 'RESOLVED - FT' then concat(U2.first_name,' ',U2.last_name) END ) as resolved_user, 

      c.updated_date as updated_date,
      concat(u.first_name,' ',u.last_name) as last_updated_by,
      IF(uv.status IS NOT NULL, 'Yes', 'No') as user_visit,
      fftr.reason as reason,
      fftr.notes as resolution
   FROM
      customer c
         left join user_status US
            on c.id = US.customer_id 
            left join user U2 
               on US.status_by_id = U2.id

         join form1 tcv 
            on (c.id = tcv.customer_id)

         join user_status cts 
            on c.current_status_id = cts.id
            join user u 
               on cts.status_by_id = u.id 
            left join user_status ts 
               on cts.status = ts.workflow_state

         left join change_info cfi 
            on c.id = cfi.customer_id

         left join user_status lus 
            ON c.current_status_id = lus.id
            left join user updBy 
               on lus.status_by_id = updBy.id

         left join change tc_fftr 
            ON c.id = tc_fftr.customer_id 
            and tc_fftr.contents LIKE 'Resolution%'
            left join form4 fftr 
               ON tc_fftr.id = fftr.change_id 
   WHERE
      c.create_date >= DATE_SUB(NOW(),INTERVAL 370 DAY)
   GROUP BY 
      customer_id

这仍然可能无法完全发挥作用,但我确信它的大部分内容都能正常工作并适应你想要获得的几乎所有内容,即使我得到了更多细节(两个日期对和相应状态的对象)动作)。