非常慢的MySQL查询

非常慢的MySQL查询,mysql,sql,join,query-optimization,Mysql,Sql,Join,Query Optimization,我很乐意接受任何关于这方面的建议——无论是重写查询,还是以不同的方式设置表 我基本上有三个表——产品表、位置表和条件表。位置表存储整个时间段内有关位置的所有信息,与条件相同。这种大规模查询的诀窍是只提取具有最新条件和位置的产品 我从这个问题中得出了大致的想法: 答案是否只是将当前位置和条件存储在主产品表中,并保留这些历史记录表,但不使用它们进行搜索?我喜欢将它们分开的想法,但当然,这个查询需要50秒才能运行,这一点都不实际 SELECT '$table' AS tablename, $tab

我很乐意接受任何关于这方面的建议——无论是重写查询,还是以不同的方式设置表

我基本上有三个表——产品表、位置表和条件表。位置表存储整个时间段内有关位置的所有信息,与条件相同。这种大规模查询的诀窍是只提取具有最新条件和位置的产品

我从这个问题中得出了大致的想法:

答案是否只是将当前位置和条件存储在主产品表中,并保留这些历史记录表,但不使用它们进行搜索?我喜欢将它们分开的想法,但当然,这个查询需要50秒才能运行,这一点都不实际

SELECT 
'$table' AS tablename, 
$table.id, 
product_name, 
$table.status,
CL.event AS last_event,
CONCAT_WS(' ', CL.location, CL.floor, CL.bin, CL.bay) AS current_loc,
CC.status AS current_cond
FROM $table

LEFT OUTER JOIN
    (SELECT DISTINCT
        C.work_type,
        C.work_id,
        C.status,
        C.inspected_timestamp
        FROM
        (SELECT 
            CONCAT(work_type, work_id) AS condition_id, 
            status,
            MAX(inspected_timestamp) as current
            FROM conditions
            GROUP BY condition_id
        ) XC
    JOIN conditions C
      on CONCAT(C.work_type, C.work_id) = XC.condition_id
      and C.inspected_timestamp = XC.current
    ) CC ON 
    $table.id = CC.work_id AND 
    CC.work_type = '$table'                         

LEFT OUTER JOIN
    (SELECT DISTINCT
        L.work_type,
        L.work_id,
        L.event,
        L.location,
        L.floor,
        L.bin,
        L.bay,
        L.timestamp
        FROM
        (SELECT
            CONCAT(work_type, work_id) AS location_id, 
            location,
            MAX(timestamp) as current
            FROM locations
            GROUP BY location_id
        ) XL
    JOIN locations L
      on CONCAT(L.work_type, L.work_id) = XL.location_id
      and L.timestamp = XL.current
    ) CL ON 
    $table.id = CL.work_id AND 
    CL.work_type = '$table'

HAVING last_event = 'Received'
我在这里添加扩展解释的结果

[0] => Array ( 
    [id] => 1 
    [select_type] => PRIMARY 
    [table] => paintings 
    [type] => ALL 
    [possible_keys] => 
    [key] => 
    [key_len] => 
    [ref] => 
    [rows] => 1159 
    [filtered] => 100.00 
    [Extra] => )

[1] => Array ( 
    [id] => 1 
    [select_type] => PRIMARY 
    [table] => 
    [type] => ALL 
    [possible_keys] => 
    [key] => 
    [key_len] => 
    [ref] => 
    [rows] => 3211 
    [filtered] => 100.00 
    [Extra] => ) 

[2] => Array ( 
    [id] => 1 
    [select_type] => PRIMARY 
    [table] => 
    [type] => ALL 
    [possible_keys] => 
    [key] => 
    [key_len] => 
    [ref] => 
    [rows] => 1870 
    [filtered] => 100.00 
    [Extra] => ) 

[3] => Array ( 
    [id] => 4 
    [select_type] => DERIVED 
    [table] => 
    [type] => ALL 
    [possible_keys] => 
    [key] => 
    [key_len] => 
    [ref] => 
    [rows] => 1868 
    [filtered] => 100.00 
    [Extra] => Using temporary )

[4] => Array ( 
    [id] => 4 
    [select_type] => DERIVED 
    [table] => L 
    [type] => ref 
    [possible_keys] => timestamp 
    [key] => timestamp 
    [key_len] => 8 
    [ref] => XL.current 
    [rows] => 5 
    [filtered] => 100.00 
    [Extra] => Using where ) 

[5] => Array ( 
    [id] => 5 
    [select_type] => DERIVED 
    [table] => locations 
    [type] => ALL 
    [possible_keys] => 
    [key] => 
    [key_len] => 
    [ref] => 
    [rows] => 3913 
    [filtered] => 100.00 
    [Extra] => Using temporary; Using filesort ) 

[6] => Array ( 
    [id] => 2 
    [select_type] => DERIVED 
    [table] => 
    [type] => ALL 
    [possible_keys] => 
    [key] => 
    [key_len] => 
    [ref] => 
    [rows] => 3191 
    [filtered] => 100.00 
    [Extra] => Using temporary ) 

[7] => Array ( 
    [id] => 2 
    [select_type] => DERIVED 
    [table] => C 
    [type] => ref 
    [possible_keys] => inspected_timestamp 
    [key] => inspected_timestamp 
    [key_len] => 8 
    [ref] => XC.current 
    [rows] => 45 
    [filtered] => 100.00 
    [Extra] => Using where ) 

[8] => Array (
     [id] => 3 
    [select_type] => DERIVED 
    [table] => conditions 
    [type] => index 
    [possible_keys] => 
    [key] => work_type_2 
    [key_len] => 316 
    [ref] => 
    [rows] => 3986 
    [filtered] => 100.00 
    [Extra] => Using index; Using temporary; Using filesort )

您可以做以下几件事:

  • 解释查询的计划。看看里面有没有表格扫描。那就是凶手
  • 查看重新排列查询是否会对解释计划结果产生影响。尽早筛选出更多记录将减少所需时间
  • 检查以确保每个WHERE子句中的列都有索引
  • 涉及的记录越多,查询的时间越长。你保留了多少历史?你说的是几排?您应该有一个策略,可以删除比保留截止日期更早的记录,并将其放入历史记录或报告架构中
  • 您能否利用触发器或视图预先计算这些值中的任何一个

  • 我在回答这个问题时纯粹是因为评论长度的限制

    我看了你的查询很长一段时间,我认为这主要是它的性质,以及它的编写方式导致查询花费了这么多时间,但我也没有看到任何明显错误的地方

    在一些地方,您通过分组获得摘要行,然后将这些查询自连接回来,虽然我不完全理解表或数据的设计,但正如解释所示,这将是非常昂贵的。所以这就是表格扫描。制作临时表并对其进行排序的成本更高,这一点您也是对的

    因此,如果这些值是预先汇总并在汇总表中可访问的,并且所花费的时间是不可接受的,那么这些值将有很大帮助。当您查看解释时,请注意行数,因为这会让您很好地了解查询所做的是否合理

    此外,根据定义,末尾的having子句也不会被优化。如果有一种方法可以将其移动到where子句或作为其中一个联接中的条件,那么您有机会显著改进查询计划,但考虑到摘要的成本,这仍然需要一些时间


    在这一点上,我唯一能建议的是将其分解成小块,看看是否可以优化各个组件,然后重新组装

    正如@gview所解释的,有许多因素帮助这个查询变得异常缓慢。除了他在回答中提到的所有这些之外,在两个表中还使用了
    CONCAT()
    函数,随后将结果用于连接这两个派生表

    如果您只想显示表
    产品
    中的行,其中只有
    位置
    中的最新相关行和
    条件
    中的最新相关行,则可以使用以下方法(这只有最新的
    条件的逻辑,对于最新的
    位置
    ,您需要另一个类似的
    左连接
    ):


    您应该做的第一件事是发出一个解释扩展查询…并包含此信息。显示创建表…对于涉及的表也不会有任何影响。我已经添加了扩展解释结果。感谢您的建议。我看到很多临时表,可能是创建这些表的问题。这是
    解释扩展
    。我添加了解释AIN扩展结果。我没有看到任何表扫描,但有很多派生表和使用临时表。这可能会减慢速度。不过你是对的,我肯定可以缩小一些内部查询。比如,因为我只搜索“已接收”在地理位置上,我可以摆脱所有不属于我的。谢谢,我很感激你的洞察力……而且我会更感激你。TBH,这只是一个答案;)
    SELECT 
      t.id, 
      t.product_name, 
      t.status,
      cc.status AS current_cond
    FROM 
          $table AS t
      LEFT OUTER JOIN
          ( SELECT c.*
            FROM 
                  conditions AS c
              JOIN
                  ( SELECT 
                      work_id, 
                      MAX(inspected_timestamp) as current_ts
                    FROM conditions mc
                    WHERE work_type = '$table'
                    GROUP BY condition_id
                  ) AS mc
                ON  mc.work_id = c.work_id
                AND mc.current_ts = c.inspected_timestamp 
            WHERE c.work_type = '$table'
          ) AS cc  
        ON cc.work_id = t.id