所以我有这个项目扩展现有的代码库,它建立在MySQL数据库上。 我有一个表格,其元组代表建筑物中的位置,我正在制作一个表格,用于表示在图形中连接这些位置以进行寻路的边缘。它只是一个简单的双列表,每列都有一个ID,它是一个引用位置表的外键。总而言之,情况是这样的:
CREATE TABLE node (
ID int(10) AUTO_INCREMENT NOT NULL,
(...)
PRIMARY KEY(ID)
);
CREATE TABLE edge(
ID_1 int(10),
ID_2 int(10),
FOREIGN KEY (ID_1) REFERENCES node(ID),
FOREIGN KEY (ID_2) REFERENCES node(ID)
);
现有的假设是图形是对称的,即如果节点A具有到节点B的边缘,则节点B必须具有到节点A的边缘。单向门的情况在这里被忽略但似乎不是适用于我的域名。因此,给定节点A和B连接,它们的连接可以以三种方式中的任何一种存储在边缘表中:
{(A,B)}
{(B,A)}
{(A,B),(B,A)}
我使用此表回答的问题是“给定此节点,它的邻居是哪些节点?”目前我的应用程序使用这样的查询来做到这一点:
SELECT * FROM node
WHERE ID IN(
SELECT ID_2
FROM edge
WHERE ID_1=?
UNION
SELECT ID_1
FROM edge
WHERE ID_2=?
);
然而,我的直觉是使用CHECK约束来确保只能存储后一种结构MySQL apparently doesn't support。从该答案来看,为了模拟这样的约束,我必须为每个操作编写触发器,以保持每个边缘以两种顺序存储。优点是它可以按照您自然的预期执行更多操作,并且只需
即可回答问题SELECT * FROM node
WHERE ID IN(
SELECT ID_2
FROM edge
WHERE ID_1=?
);
一旦我读到有关模拟CHECK的触发器,我就和朋友讨论过了,他建议确保自反存储会浪费(使存储使用量增加一倍),应该由应用程序来正确处理数据库。现在我有点不确定什么是最好的解决方案 - 如果数据库通过使用触发器加倍插入和删除来确保反射性,或者应用程序是否应该继续读取未反复存储的数据以使其看起来像是?允许我的数据库以多种方式表示相同的数据让我有点担心。那是不合理的吗? UNION等会对任何可观的性能造成影响吗?
(针对相当小的站点,该系统不太可能通过数万个节点,典型节点最多有6个边缘)。
答案 0 :(得分:0)
实际上,在您的情况下,将每个连接视为一个连接也是可能的(您可以在需要时阻止它!)。如果房间之间有多个连接怎么办?就像一个房间有2个独立的门进入同一个大厅?
anyhoo这些都是很好玩的...
就个人而言,我会根据方向存储每个连接,所以如果a和b之间有一个双向门,我会这样存储
tbl_connections
current_room_id edge connecting_room_id
1 north 2
2 south 1
1 east 3
1 west 4
4 east 1
1 south 5
是的,如果您有可用的数据,我会包括哪个边缘连接 - 它可能会在以后决定包含它时帮助.... (在上述结构中,您可以从1到3但不是3到1)。
存储就像这样,你可以使用:
简单地得到一个房间邻居(和方向)SELECT connecting_room, edge
FROM tbl_connections
WHERE current_room_id = 1;
这应该给你:
2, north
3, east
4, west
5, south
您还可以根据您所在的房间以及您打算使用此架构通过的边缘来映射路径。
在您调用它时存储自反数据是一种非常常见的解决方案,在这种情况下,我认为它是正确的方法。