查询花费的时间太长而不使用索引

时间:2018-08-23 21:09:05

标签: mysql performance query-performance mysql-5.6

我们有一个事件服务,该服务返回按ID和事件时间戳过滤并按主列排序的事件。

此表中大约有1.5 GB的数据

查询:

SELECT event.eventID, event.orgID, event.objectType, event.action, event.objectID, 
       event.logEventID, event.eventTimestamp, event.userID, event.source, 
       event.additionalDetails, event.insertByUserID, event.insertDateTime, 
       event.modifyByUserID, event.modifyDateTime 
  FROM event 
 WHERE event.orgID = 100 
   AND event.eventTimestamp >= 1535046151000 
ORDER BY event.eventID ASC limit 10001;

以上查询需要14秒才能执行。

如果我删除ORDER BY event.eventID ASC,则需要0.01秒

当前索引位于主列idx1(eventID)上。我们添加了第二个索引idx2(orgID,eventTimestamp),但仍然看不到性能提高。

除非使用“ USE Hint”指定,否则查询不使用新索引。使用提示并提供idx2需要7秒钟。

我们使用的是mysql版本5.6

是否有缩短执行时间的想法?

3 个答案:

答案 0 :(得分:1)

最大的麻烦是Using filesort操作,我们应该看看是否可以获取按“索引顺序”返回的行,以避免该操作。

我很想添加一个索引:

... ON `event` (`orgid`,`eventid`,`eventtimestamp`)

我还将尝试调整查询。尽管不是绝对必要,但我们可以在orgid子句中包含ORDER BY列,因为WHERE子句中的条件可以保证我们有一个单一的值。

 ORDER BY event.orgid ASC, event.eventid ASC

此处旨在为优化器提供尽可能多的信息,即有一个合适的索引可以满足ORDER BY子句。

使用EXPLAIN查看执行计划。

我们正试图让MySQL在orgid上使用索引范围扫描,以eventid的“索引”顺序返回行。然后丢弃不满足eventtimestamp上条件的行。

SELECT event.eventid
     , event.orgid
     , event.objecttype
     , event.action
     , event.objectid
     , event.logeventid
     , event.eventtimestamp
     , event.userid
     , event.source
     , event.additionaldetails
     , event.insertbyuserid
     , event.insertdatetime
     , event.modifybyuserid
     , event.modifydatetime
  FROM event
 WHERE event.orgid = 100
   AND event.eventtimestamp >= 1535046151000
 ORDER
    BY event.orgid ASC 
     , event.eventid ASC
 LIMIT 10001

如果这还不足以避免执行“使用文件排序”操作,那么我们可以尝试将eventtimestamp上的条件从WHERE子句移到HAVING子句中。 (将AND关键字替换为HAVING。)


省略eventtimestamp的索引可能足以获取合理的执行计划。

代替

... ON `event` (`orgid`,`eventid`,`eventtimestamp`)

这可能同样有效

... ON `event` (`orgid`,`eventid`)

答案 1 :(得分:0)

无需同时使用WHEREHAVING。只需使用WHERE orgID = 100 AND eventTimestamp >= somevalue

SELECT lots of stuff ORDER BY something LIMIT count是一个臭名昭著的性能反模式。为什么?它对整个行进行了排序,以丢弃其中的大部分。

您可以使用延迟连接更好地做到这一点。在子查询中获取所需行的PK值,然后检索详细信息。

为子查询尝试类似的操作。

         SELECT eventID
           FROM event
          WHERE orgID = 100
            AND eventTimestamp >= somevalue
          ORDER BY eventID
          LIMIT somecount

您可以使用(orgID, eventTimestamp)上的复合索引来加速此查询。 (如果表使用MyISAM,则像这样(orgID, eventTimestamp, eventID)那样将PK包括在索引中。

然后执行此操作以从所需的行中获取数据详细信息。

SELECT event.eventID, event.orgID, event.objectType, event.action, event.objectID, 
       event.logEventID, event.eventTimestamp, event.userID, event.source, 
       event.additionalDetails, event.insertByUserID, event.insertDateTime, 
       event.modifyByUserID, event.modifyDateTime 
  FROM event
  JOIN (
         SELECT eventID
           FROM event
          WHERE orgID = 100
            AND eventTimestamp >= somevalue
          ORDER BY eventID
          LIMIT somecount
       ) sel ON event.eventID  = sel.eventID
 ORDER BY event.eventID

之所以起作用,是因为它仅对主键值进行排序,然后丢弃。那便宜。

如果您的eventTimestamp和eventID值都严格按升序排列,则还有另一种可能的优化方法。也就是说,如果您插入的每一行都有当前时间戳,则可以利用这一事实。

SELECT event.eventID, event.orgID, event.objectType, event.action, event.objectID, 
       event.logEventID, event.eventTimestamp, event.userID, event.source, 
       event.additionalDetails, event.insertByUserID, event.insertDateTime, 
       event.modifyByUserID, event.modifyDateTime 
  FROM event
  JOIN (
         SELECT eventID
           FROM event
          WHERE orgID = 100
            AND eventID >= (SELECT MIN(eventID) 
                              FROM event 
                             WHERE eventTimestamp >= somevalue)
          ORDER BY eventID
          LIMIT somecount
       ) sel ON event.eventID  = sel.eventID
 ORDER BY event.eventID

对这种查询使用orgID上的索引和eventTimestamp上的另一个索引。之所以可以使用它,是因为时间戳大于起始时间戳的每一行都具有eventID> =第一行中符合时间标准的eventID。

希望您的eventTimestamp列具有BIGINTDOUBLE数据类型。 Javascript时间戳(自UNIX时代以来的毫秒数)不适合32位整数。如果索引正确,则较大的数据类型不会对性能造成太大影响。

答案 2 :(得分:0)

同时具备以下两个条件:

INDEX(orgid, eventTimestamp)
INDEX(orgid, eventID)

优化器可以使用它们之一,并且可以根据统计信息选择更好的一个。向其中任一列添加额外的列将不会加快 this 查询。第二个索引将避免文件排序,但可能可能不会更快。

如果输出要转到网页,则我认为LIMIT 10001太笨拙了。