检查SQL查询中是否正在使用索引?

时间:2015-05-30 00:24:06

标签: mysql sql indexing phpmyadmin

我的数据库中有两个表格大致如下:

运动:

Timestamp            visitorID Type        X   Y  
2012-03-02 11:02:30  379      pedestrian  32  46
2012-03-01 12:32:41  654      pedestrian  54  56
2012-03-02 07:02:16  789      pedestrian  39  52 

沟通:(致电)

Timestamp            senderID     toID GeneralLocation 
2012-03-02 09:02:30  878          674        Grasslands 
2012-03-02 11:30:01  456          213        Tundra 
2012-03-02 07:02:12  789          654        Mountains 

我运行了这个查询:

SELECT c.senderID,c.timestamp,m.timestamp,m.x,m.y
FROM communication c
JOIN movement m ON c.senderID = m.visitorID
WHERE m.timestamp = (SELECT MIN(mm.timestamp)
                 FROM movement mm 
                 WHERE mm.timestamp >= c.timestamp); 

这基本上可以找到给定通信时间戳的最接近的移动时间戳。我想要做的是找到某个senderID拨打电话的位置。由于并非每个visitorID都拨打电话,因此首先会检查c.senderID = m.visitorID。然后,它会遍历communication的每一行,并找到movement timestamp表中每个timestamp最接近的communication

然后我使用EXPLAIN来查看我是否正在使用我的索引......我得到了这个:

enter image description here

这是否意味着在第二行中我的索引没有被正确使用?我现在拥有的索引是:

CREATE INDEX timestamp ON DBName.movement (timestamp); 

CREATE INDEX ctstamp ON DBName.communication (timestamp);

CREATE INDEX SID_tstamp ON communication (senderID, timestamp);

CREATE INDEX VID_tstamp ON movement (visitorID, timestamp);

基本上,在MovementCommunication表中,每个timestamp都有一个索引。然后,每个IDtimestamp都有一个。

我的问题基本上是,我的索引出了什么问题,如何修改它们以便可以使用它们?

我是SQL的新手,所以非常感谢任何帮助,谢谢!

修改

enter image description here

1 个答案:

答案 0 :(得分:1)

不,它正在使用索引。 refkeylen告诉我们。

我认为您可能会对EXPLAIN输出中其他行的Extra列中的Using index感到困惑。这意味着完全从索引中满足查询,而无需访问底层数据页。

如果你担心性能,那就是我们需要关注的相关子查询。 (对该子查询中c.的引用。)

修改

我认为你的查询应该在mm.visitorID = c.senderID上包含一个谓词(这是基于我们通常在这样的查询中看到的规范模式。

您希望位置(xy)位于timestamp之后m位于c的时间戳之后......并且你有一个条件(谓词)将visitorID与senderID匹配。我想你想在检查“最早”时间戳时重复相同的条件。 (否则,您可以获得其他访客ID的时间戳)

只要有一个合适的索引

,一个更改可能会加快您的查询速度

... ON运动(vistorID,时间戳)

实际上在该索引中包含xy也会让这些值从索引中返回,并且您将在EXPLAIN输出中获得Using index

考虑到这一变化,这是重写时的第一次削减,避免了相关的子查询。

SELECT c.senderID
     , c.timestamp
     , m.timestamp  AS m_timestamp
     , m.x
     , m.y
  FROM ( SELECT mc.senderID
              , mc.timestamp
              , MIN(mm.timestamp) AS min_timestamp
           FROM communication mc                    --< table alias mc
           JOIN movement mm                         --< table alias mm
             ON mm.visitorID  = mc.senderID
             ON mm.timestamp >= mc.timestamp
          GROUP BY mc.senderID, mc.timestamp
          ORDER BY mc.senderID, mc.timestamp
       ) r                                          --< table alias r
  JOIN movement m                                   --< table alias m
       ON  m.visitorID   = r.senderID
       AND m.timestamp   = r.min_timestamp
  JOIN communication c
       ON  c.senderID    = r.senderID
       AND c.timestamp   = r.timestamp
 ORDER BY r.senderID, r.timestamp

此处,内嵌视图(别名为r的任务是从movement获取最早的时间戳。这将把结果转化为“临时”表格。 (我暂时引用了引号;它在查询期间是临时的,但它在MySQL白话中被称为派生表。)

有一个GROUP BY操作;希望我们可以避免Using filesort操作并使用合适的索引进行优化。

一旦我们拥有了它,它应该只是cm的索引查找。

我再次看着这个。我们实际上不需要加入c,我们已经从内联视图中获取了值。

我说这是一个裂缝,让我知道它做了多大的烟球。 (不保证,因为没有经过测试。)

  SELECT r.senderID
       , r.timestamp
       , m.timestamp AS m_timestamp
       , m.x
       , m.y
    FROM ( SELECT mc.senderID
                , mc.timestamp
                , MIN(mm.timestamp) AS min_timestamp
             FROM communication mc                     -- < table alias mc
             JOIN movement mm                          -- < table alias mm
               ON mm.visitorID  = mc.senderID
               ON mm.timestamp >= mc.timestamp
            GROUP BY mc.senderID, mc.timestamp
            ORDER BY mc.senderID, mc.timestamp
         ) r                                           -- < table alias r
    JOIN movement m                                    -- < table alias m
         ON  m.visitorID   = r.senderID
         AND m.timestamp   = r.min_timestamp
   ORDER BY r.senderID, r.timestamp

编辑在前两次查询中将无效引用c.更正为mc.