优化查看大量数据的MySQl查询

时间:2017-06-21 20:00:20

标签: mysql sql database

所以我有一个我需要分析的错误日志。该日志是一个包含大约250万行的巨大文件。

在该错误日志中有以下字段:

EVENT_ATTRIBUTE,显示收集该设备的设备的名称   信息。

EVENT_SEVERITY,显示1到5之间的数字。在此栏中,我需要找到1,2,4和5的数量。

这是表Im的屏幕截图的链接:

https://i.stack.imgur.com/Yk4dq.png

我基本上需要获取event_attribute并计算event_severity的数量并将它们放在单独的列中。因此,将分割与每个event_attribute相关的1和2的数量,以便每个传感器(event_attribute)选择的每种类型的错误数量。

目前这是我的代码:

    SELECT LEFT(EVENT_ATTRIBUTE, LOCATE('(', EVENT_ATTRIBUTE, 1)-1) AS 
    SensorName, 
       SUM(EVENT_SEVERITY = 1) CODE_1,
       SUM(EVENT_SEVERITY = 2) CODE_2,
       SUM(EVENT_SEVERITY = 4) ERROR_4,
       SUM(EVENT_SEVERITY = 5) ERROR_5
    FROM taddmapp.disc_event
    WHERE EVENT_SEVERITY = 5 OR EVENT_SEVERITY = 4 OR EVENT_SEVERITY = 2 OR 
      EVENT_SEVERITY = 1 
    GROUP BY LEFT(EVENT_ATTRIBUTE, LOCATE('(', EVENT_ATTRIBUTE, 1)-1);

代码的LEFT(EVENT_ATTRIBUTE, LOCATE('(', EVENT_ATTRIBUTE, 1)-1)部分只丢弃正在使用的传感器的IP地址,另一部分选择总和状态代码的数量。代码运行良好,为我带来了我需要的结果,但唯一的问题是它需要太长时间了。我前几天运行它,执行此查询花了一个多小时。我想知道是否有任何方法可以优化此查询。我的SQL不太好,所以我需要优化帮助。

感谢您的时间!

3 个答案:

答案 0 :(得分:1)

您在表格的每一行调用了几个字符串函数(LEFT()LOCATE());这肯定会影响性能。如果您可以向表中添加另一个字段以永久保存您正在提取的子字符串/值,则可以使用该字段,而无需为每个此类查询提取该字段;并允许索引字段以提供更多的性能优势。

如果使新字段为空并且默认为null,则可以运行查询以使用提取的值更新较新的行;或者更好,创建一个插入前触发器,在插入结果时计算字段值。

答案 1 :(得分:1)

如果不向表中添加列,则我们可以尝试重写查询以有效使用以EVENT_ATTRIBUTE作为前导列的索引。使用这样的索引:

... ON taddmapp.disc_event (EVENT_ATTRIBUTE,EVENT_SEVERITY)

我们有机会让MySQL使用该索引并避免使用“使用filesort”操作来满足内部查询中的GROUP BY。

SELECT SUBSTRING_INDEX(t.EVENT_ATTRIBUTE,'(',1) AS 
SensorName
     , SUM(t.CODE_1) AS CODE_1
     , SUM(t.CODE_2) AS CODE_2
     , SUM(t.ERROR_4) AS ERROR_4
     , SUM(t.ERROR_5) AS ERROR_5
  FROM ( SELECT e.EVENT_ATTRIBUTE
              , SUM(e.EVENT_SEVERITY = 1) AS CODE_1
              , SUM(e.EVENT_SEVERITY = 2) AS CODE_2
              , SUM(e.EVENT_SEVERITY = 4) AS ERROR_4
              , SUM(e.EVENT_SEVERITY = 5) AS ERROR_5
           FROM taddmapp.disc_event e
          WHERE e.EVENT_SEVERITY IN (1,2,4,5)
          GROUP BY e.EVENT_ATTRIBUTE
       ) t
 GROUP
    BY SUBSTRING_INDEX(t.EVENT_ATTRIBUTE,'(',1)

注意:外部查询上的GROUP BY仍然需要“使用filesort”操作,但这里的目标是让外部查询对更小的行集进行操作(假设内联视图中的GROUP BY)将这250万行折叠成一个更合理的大小。)

如果我们只有一个裸柱,例如EVENT_ATTRIBUTE_PREFIX只填充了我们感兴趣的EVENT_ATTRIBUTE的前导部分,我们可以避免使用内联视图。假设我们有那个列,它是索引中的前导列,例如

... ON taddmapp.disc_event (EVENT_ATTRIBUTE_PREFIX,EVENT_SEVERITY)

然后MySQL可以使用该索引来满足GROUP BY操作,而不需要使用“使用filesort”操作,使用如下查询:

SELECT e.EVENT_ATTRIBUTE_PREFIX  AS SensorName
     , SUM(e.EVENT_SEVERITY = 1) AS CODE_1
     , SUM(e.EVENT_SEVERITY = 2) AS CODE_2
     , SUM(e.EVENT_SEVERITY = 4) AS ERROR_4
     , SUM(e.EVENT_SEVERITY = 5) AS ERROR_5
  FROM taddmapp.disc_event e
 WHERE e.EVENT_SEVERITY IN (1,2,4,5)
 GROUP BY e.EVENT_ATTRIBUTE_PREFIX

答案 2 :(得分:1)

简化WHERE条款:

SELECT LEFT(EVENT_ATTRIBUTE, LOCATE('(', EVENT_ATTRIBUTE, 1)-1) AS 
SensorName, 
       SUM(EVENT_SEVERITY = 1) as CODE_1,
       SUM(EVENT_SEVERITY = 2) as CODE_2,
       SUM(EVENT_SEVERITY = 4) as ERROR_4,
       SUM(EVENT_SEVERITY = 5) as ERROR_5
FROM taddmapp.disc_event
WHERE EVENT_SEVERITY IN (1, 2, 4, 5)
GROUP BY LEFT(EVENT_ATTRIBUTE, LOCATE('(', EVENT_ATTRIBUTE, 1)-1);

您可以使用disc_event(event_severity, event_attribute)上的索引来提高效果。

然后由于group by而无法做到。