我的解决方案有两个警告:
1)您说您可以添加索引但不能更改架构,所以我不确定这是否适合您,因为您不能在 MySQL 中拥有基于函数的索引,您需要在 Table 上创建一个额外的列B. 2) 此解决方案的另一个警告是您必须为表 B 使用 MyISAM 引擎。如果您不能使用 MyISAM,那么此解决方案将不起作用,因为空间索引仅支持 MyISAM。
因此,假设上述两个对您来说不是问题,以下应该可以工作并为您提供良好的性能:
此解决方案利用 MySQL 对空间数据的支持(请参阅此处的文档)。虽然可以将空间数据类型添加到各种存储引擎中,但为了获得所需的性能,空间 R-Tree 索引(请参阅此处的文档)仅支持 MyISAM。另一个限制是空间数据类型仅适用于数字数据,因此您不能将此技术用于基于字符串的范围查询。
我不会详细介绍空间类型如何工作以及空间索引如何有用的理论细节,但您应该查看Jeremy Cole 的解释,了解如何使用空间数据类型和索引进行 GeoIP 查找。如果您需要原始性能并且可以放弃一些准确性,还请查看评论,因为它们提出了一些有用的观点和替代方案。
基本前提是我们可以使用 start/end 并使用它们中的两个创建四个不同的点,一个用于在 xy 网格上以 0,0 为中心的矩形的每个角,然后快速查找空间index 来确定我们关心的特定时间点是否在矩形内。如前所述,请参阅 Jeremy Cole 的解释,以更全面地了解其工作原理。
在您的特定情况下,我们将需要执行以下操作:
1) 将表更改为 MyISAM 表(请注意,除非您完全了解此类更改的后果,例如缺少与 MyISAM 关联的事务和表锁定行为,否则不应这样做)。
alter table B engine = MyISAM;
2)接下来我们添加将保存空间数据的新列。我们将使用多边形数据类型,因为我们需要能够容纳一个完整的矩形。
alter table B add column time_poly polygon NOT NULL;
3) 接下来,我们用数据填充新列(请记住,任何更新或插入表 B 的进程都需要进行修改,以确保它们也填充新列)。由于开始和结束范围是时间,我们需要使用 unix_timestamp 函数将它们转换为数字(有关其工作原理,请参阅此处的文档)。
update B set time_poly := LINESTRINGFROMWKB(LINESTRING(
POINT(unix_timestamp(start_time), -1),
POINT(unix_timestamp(end_time), -1),
POINT(unix_timestamp(end_time), 1),
POINT(unix_timestamp(start_time), 1),
POINT(unix_timestamp(start_time), -1)
));
4) 接下来我们将空间索引添加到表中(如前所述,这仅适用于 MyISAM 表,并且会产生错误“ERROR 1464 (HY000): The used table type doesn't support SPATIAL index”)。
alter table B add SPATIAL KEY `IXs_time_poly` (`time_poly`);
5)接下来,您将需要使用以下选择,以便在查询数据时使用空间索引。
SELECT A.id, B.id
FROM A inner join B force index (IXs_time_poly)
ON MBRCONTAINS(B.time_poly, POINTFROMWKB(POINT(unix_timestamp(A.event_time), 0)));
强制索引可以 100% 确保 MySQL 将使用索引进行查找。如果一切顺利,在上述选择上运行解释应该显示类似于以下内容:
mysql> explain SELECT A.id, B.id
-> FROM A inner join B force index (IXs_time_poly)
-> on MBRCONTAINS(B.time_poly, POINTFROMWKB(POINT(unix_timestamp(A.event_time), 0)));
+----+-------------+-------+------+---------------+------+---------+------+---------+-------------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+---------+-------------------------------------------------+
| 1 | SIMPLE | A | ALL | NULL | NULL | NULL | NULL | 1065 | |
| 1 | SIMPLE | B | ALL | IXs_time_poly | NULL | NULL | NULL | 7969897 | Range checked for each record (index map: 0x10) |
+----+-------------+-------+------+---------------+------+---------+------+---------+-------------------------------------------------+
2 rows in set (0.00 sec)
请参阅 Jeremy Cole 的分析,了解与 between 子句相比此方法的性能优势的详细信息。
如果您有任何问题,请告诉我。
谢谢,
-蘸