检查 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);
所以基本上,在 Movement
和 Communication
table 中,每个 timestamp
都有一个索引。然后 ID
和 timestamp
各有一个。
我的问题基本上是,我的索引有什么问题,我该如何修改它们才能使用它们?
我是 SQL 的新手,如有任何帮助,我们将不胜感激,谢谢!!
编辑
不,它正在使用索引。 ref
和 keylen
告诉我们。
我想您可能对 EXPLAIN 输出中其他行的 Extra 列中的 Using index
感到困惑。这意味着查询完全由索引满足,无需访问底层数据页。
如果您关心性能,那么我们需要关注的是相关子查询。 (该子查询中对 c.
的引用。)
编辑
我认为您的查询应该包含关于 mm.visitorID = c.senderID
的谓词(这是基于我们通常在此类查询中看到的规范模式。
您似乎想要位置 (x
,y
) 最早 timestamp
来自 m
,在 c
上的时间戳之后。 .. 并且您有一个将 visitorID 与 senderID 相匹配的条件(谓词)。我认为您想在检查 "earliest" 时间戳时重复相同的条件。 (否则,您可以获得其他一些访客 ID 的时间戳)
给定一个 suitable 索引
,仅此一项更改可能会稍微加快您的查询速度
...开启移动(vistorID、时间戳)
实际上在该索引中也包括 x
和 y
将使这些值从索引返回,并且您将在 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 索引对其进行优化。
一旦我们有了它,它应该只是对 c
和 m
.
的索引查找
我又在看这个了。我们实际上不需要连接到 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.
。
我的数据库中有两个 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);
所以基本上,在 Movement
和 Communication
table 中,每个 timestamp
都有一个索引。然后 ID
和 timestamp
各有一个。
我的问题基本上是,我的索引有什么问题,我该如何修改它们才能使用它们?
我是 SQL 的新手,如有任何帮助,我们将不胜感激,谢谢!!
编辑
不,它正在使用索引。 ref
和 keylen
告诉我们。
我想您可能对 EXPLAIN 输出中其他行的 Extra 列中的 Using index
感到困惑。这意味着查询完全由索引满足,无需访问底层数据页。
如果您关心性能,那么我们需要关注的是相关子查询。 (该子查询中对 c.
的引用。)
编辑
我认为您的查询应该包含关于 mm.visitorID = c.senderID
的谓词(这是基于我们通常在此类查询中看到的规范模式。
您似乎想要位置 (x
,y
) 最早 timestamp
来自 m
,在 c
上的时间戳之后。 .. 并且您有一个将 visitorID 与 senderID 相匹配的条件(谓词)。我认为您想在检查 "earliest" 时间戳时重复相同的条件。 (否则,您可以获得其他一些访客 ID 的时间戳)
给定一个 suitable 索引
,仅此一项更改可能会稍微加快您的查询速度...开启移动(vistorID、时间戳)
实际上在该索引中也包括 x
和 y
将使这些值从索引返回,并且您将在 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 索引对其进行优化。
一旦我们有了它,它应该只是对 c
和 m
.
我又在看这个了。我们实际上不需要连接到 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.
。