我的数据库中有两个表格大致如下:
运动:
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
来查看我是否正在使用我的索引......我得到了这个:
这是否意味着在第二行中我的索引没有被正确使用?我现在拥有的索引是:
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
表中,每个timestamp
都有一个索引。然后,每个ID
和timestamp
都有一个。
我的问题基本上是,我的索引出了什么问题,如何修改它们以便可以使用它们?
我是SQL的新手,所以非常感谢任何帮助,谢谢!
修改
答案 0 :(得分:1)
不,它正在使用索引。 ref
和keylen
告诉我们。
我认为您可能会对EXPLAIN输出中其他行的Extra列中的Using index
感到困惑。这意味着完全从索引中满足查询,而无需访问底层数据页。
如果你担心性能,那就是我们需要关注的相关子查询。 (对该子查询中c.
的引用。)
修改强>
我认为你的查询应该在mm.visitorID = c.senderID
上包含一个谓词(这是基于我们通常在这样的查询中看到的规范模式。
您希望位置(x
,y
)位于timestamp
之后m
位于c
的时间戳之后......并且你有一个条件(谓词)将visitorID与senderID匹配。我想你想在检查“最早”时间戳时重复相同的条件。 (否则,您可以获得其他访客ID的时间戳)
只要有一个合适的索引
,一个更改可能会加快您的查询速度... ON运动(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
获取最早的时间戳。这将把结果转化为“临时”表格。 (我暂时引用了引号;它在查询期间是临时的,但它在MySQL白话中被称为派生表。)
有一个GROUP BY
操作;希望我们可以避免Using filesort
操作并使用合适的索引进行优化。
一旦我们拥有了它,它应该只是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
编辑在前两次查询中将无效引用c.
更正为mc.
。