抱歉篇幅太长,想给出完整的描述!我需要显示一份报告,其中显示有关另一个表中的 id 的一些信息,以及当有人在 x 天内从一个国家/地区更改国家/地区时。请注意我如何可以在表中多次输入相同的国家/地区条目(因为信息会定期查询多次,但在此期间它们可能没有移动),并且还可以有不同的国家/地区条目(因为它们改变国家)。
数据的快速解释:我有下表:
CREATE TABLE IF NOT EXISTS `country` (
`id` mediumint(8) unsigned NOT NULL,
`timestamp` datetime NOT NULL,
`country` varchar(64) DEFAULT NULL,
PRIMARY KEY (`id`,`timestamp`),
KEY `country` (`country`),
KEY `timestamp` (`timestamp`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
条目是这样的:
41352 2012-03-26 15:46:01 Jamaica
41352 2012-03-05 22:49:41 Jamaican Applicant
41352 2012-02-26 15:46:01 Jamaica
41352 2012-02-16 12:11:19 Jamaica
41352 2012-02-05 23:00:30 Jamaican Applicant
该表目前大约有大约 214,590 行,但一旦将测试数据替换为真实数据,就会有数百万行。
我想要的是关于从 y 时间离开 x 国家的每个人的一些信息。假设它是在上面的数据上运行的,我希望它是这样输出的:
id name last country TIMESTAMP o_timestamp
41352 Sweet Mercy Jamaica 2012-03-26 15:46:01 2012-03-05 22:49:41
41352 Sweet Mercy Jamaica 2012-02-16 12:11:19 2012-02-05 23:00:30
其中 o_timestamp 比某个日期(假设为 100)更新,国家是他们搬到的地方,他们来自的旧国家(未显示)是我传入查询的任何内容(牙买加申请人基于上述数据)。
我开发了以下查询来满足要求,并使用某个 id 进行测试:
SELECT a.id,
c.name,
c.last,
a.country,
a.timestamp,
b.timestamp AS o_timestamp
FROM country a
INNER JOIN user_info c
ON ( a.id = c.id )
LEFT JOIN country AS b
ON ( a.id = b.id
AND a.timestamp != b.timestamp
AND a.country != b.country )
WHERE b.timestamp = (SELECT c.timestamp
FROM country c
WHERE a.id = c.id
AND a.timestamp > c.timestamp
ORDER BY c.timestamp DESC
LIMIT 1)
AND a.id = 965
我完成了这个(总共 7 个,查询耗时 0.0050 秒)
一个解释扩展揭示了以下内容:
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY c const PRIMARY PRIMARY 3 const 1 100.00
1 PRIMARY a ref PRIMARY PRIMARY 3 const 16 100.00
1 PRIMARY b eq_ref PRIMARY,timestamp PRIMARY 11 const,func 1 100.00 Using where
2 DEPENDENT SUBQUERY c index PRIMARY,timestamp timestamp 8 NULL 1 700.00 Using where; Using index
所以我觉得我很好,然后突然出现:
SELECT a.id,
c.name,
c.last,
a.country,
a.timestamp,
b.timestamp AS o_timestamp
FROM country a
INNER JOIN user_info c
ON ( a.id = c.id )
LEFT JOIN country AS b
ON ( a.id = b.id
AND a.timestamp != b.timestamp
AND a.country != b.country )
WHERE b.timestamp = (SELECT c.timestamp
FROM country c
WHERE a.id = c.id
AND a.timestamp > c.timestamp
ORDER BY c.timestamp DESC
LIMIT 1)
AND b.country = "whatever" AND timestamp > DATE_SUB(NOW(), INTERVAL 7 DAY)
在一个有 200 条记录但从未完成的国家(在下午和晚上外出之后,
回家总共大约 8 小时)对于一个在数据库中有 9000 条记录的国家/地区。在真实数据中,一个国家可能会轻松 10000 倍。100k不会不合理。
所以我确实解释了扩展,并得到了这个:
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY <derived2> ALL NULL NULL NULL NULL 3003 100.00
1 PRIMARY c eq_ref PRIMARY PRIMARY 3 b.id 1 100.00
1 PRIMARY a ref PRIMARY PRIMARY 3 b.id 7 100.00 Using where
3 DEPENDENT SUBQUERY c index PRIMARY,timestamp timestamp 8 NULL 1 700.00 Using where; Using index
2 DERIVED country range country,timestamp country 195 NULL 474 100.00 Using where; Using index
所以它看起来更大,但并非不合理。
[删除了空间的配置变量,如果需要,请告诉我以及性能信息,因为它可能是一个查询。]
如果我错过了什么,请告诉我。