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

Checking whether indexes are being used in SQL query?

我的数据库中有两个 table,大致如下所示:

运动:

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 的每一行,并为 communication table 中的每个 timestamp 找到最接近的 movement timestamp

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

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

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 table 中,每个 timestamp 都有一个索引。然后 IDtimestamp 各有一个。

我的问题基本上是,我的索引有什么问题,我该如何修改它们才能使用它们?

我是 SQL 的新手,如有任何帮助,我们将不胜感激,谢谢!!

编辑

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

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

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

编辑

我认为您的查询应该包含关于 mm.visitorID = c.senderID 的谓词(这是基于我们通常在此类查询中看到的规范模式。

您似乎想要位置 (x,y) 最早 timestamp 来自 m,在 c 上的时间戳之后。 .. 并且您有一个将 visitorID 与 senderID 相匹配的条件(谓词)。我认为您想在检查 "earliest" 时间戳时重复相同的条件。 (否则,您可以获得其他一些访客 ID 的时间戳)

给定一个 suitable 索引

,仅此一项更改可能会稍微加快您的查询速度

...开启移动(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 获取最早的时间戳)。这会将结果旋转成 "temporary" table。 (我将临时放在引号中;它是临时的,因为它在查询期间一直存在,但在 MySQL 方言中它被称为 derived table。)

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

一旦我们有了它,它应该只是对 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

EDIT 将前两个查询中的无效引用 c. 更正为 mc.