【问题标题】:Optimising Multiple Joins to the same table MySQL优化对同一个表 MySQL 的多个连接
【发布时间】:2015-10-25 17:14:12
【问题描述】:

我有一个查询多次加入同一个表 (user_status) 以拉回不同的状态信息。此查询的总体目标是将其转换为视图。我相信这些连接会导致查询运行时出现延迟,从而导致查询挂起。我正在尝试尽可能优化查询,但除了拥有所有这些连接之外,我不知道另一种方法。连接是左连接,因为我也想看到返回的空值。 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)

【问题讨论】:

  • 运行成功过吗?发布说明计划

标签: mysql join


【解决方案1】:

首先,列出的查询不会运行,因为您没有“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

你为什么要根据 cts.status 重新加入别名“ts”的 user_status 表。如果您有 10k 条状态为“NEW”的记录,则您将左连接到工作流状态的所有这些记录。您没有与客户 ID 关联的任何内容。但是由于您在连接链中处于优先地位,因此由 current_status_id 连接(我只能猜测是 user_status 表的自动增量 ID)。这是一个错误吗?您是否正在尝试获取“workflow_state”的一些描述。我相信这一个组件对你的表现有很大的影响。是否有不同的表(workflow_state 的别名“w”)未在此处准确反映?

现在,可能会重写。对用户状态和用户表进行一次连接,以确定各自的状态元素以及由谁以及为标准执行案例/何时...类似于...我使用“US”作为 User_Status 别名,使用“U2”作为每个相应的“用户状态”条目的通用“用户”参考。现在,注意所有的 case/when 实例。由于我只加入状态,然后加入用户表而没有特定条件,因此我可以在 FIELD 条件级别应用条件,或者为空,或者适用,并获取操作的日期和对象。

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

这仍然可能无法完全正常工作,但我相信它的大部分都可以工作并适应几乎所有你想要得到的东西,即使我得到了一些更多细节(两个日期和相应状态的人)行动)。

【讨论】:

    猜你喜欢
    • 2012-01-30
    • 1970-01-01
    • 2012-04-12
    • 1970-01-01
    • 1970-01-01
    • 2019-12-30
    • 1970-01-01
    • 2011-04-23
    • 2011-01-06
    相关资源
    最近更新 更多