Mysql 优化同一表的多个联接

Mysql 优化同一表的多个联接,mysql,join,Mysql,Join,我有一个查询,它在同一个表(user_status)中多次连接,以便提取不同的状态信息。此查询的总体目标是将其转换为视图。我相信这些连接会导致查询运行时的延迟,这会导致查询挂起。我试图尽可能地优化查询,但除了拥有所有这些连接之外,我不知道还有其他方法可以做到这一点。这些连接是左连接,因为我希望看到也返回空值。where子句筛选器将返回最长370天前的时间线的数据。我将把我的查询粘贴到下面;如有任何建议,我们将不胜感激: SELECT c.id AS customer_id, c

我有一个查询,它在同一个表(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)

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

我会确保在您的表上有以下复合索引

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)
此外,您似乎甚至没有使用指定的_ft_dis(将别名更改为ftDis)

然后,在你加入“form1”之后

为什么您要基于cts.status通过别名“ts”再次加入用户_状态表。如果您有10k条状态为“新建”的记录,则您将加入工作流状态的所有记录。您没有与客户ID关联的任何内容。但是,由于您在联接链中处于领先地位,因此由当前的_status_ID(我只能猜测它是用户_status表的自动增量ID)联接。这是个错误吗?您是否正在尝试获取“工作流状态”的描述。我相信这一部分对你的表现有很大的影响。是否有其他表格(工作流状态别名为“w”)未在此处准确反映

现在,一个可能的重写。对用户状态和用户表执行单个联接,以确定相应的状态元素,以及由谁和何时执行标准的case/when。。。类似于。。。我使用“US”表示用户状态别名,“U2”表示每个对应的“用户状态”条目的通用“用户”引用。现在,请注意所有case/when实例。因为我只加入到status表,然后是user表,没有特定的条件,所以我可以在字段条件级别应用这些条件,要么为null,要么为applicative,并获取操作的日期和用户

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

这可能还不能完全奏效,但我相信大部分都能奏效,并能满足您想要得到的几乎所有内容,即使我得到了更多的细节(两个日期和相应状态操作的负责人)。

它是否成功运行过?发布解释计划
     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
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