我有一个由5,000个单元组成的几何图,每个单元都是一个任意多边形。我的应用程序需要保存许多这样的图表。
我已确定需要使用数据库对此地图进行索引查询。加载所有地图数据对于简单查询的快速响应来说效率太低。
我已将单元格数据添加到数据库中。它有一个相当简单的结构:
CREATE TABLE map_cell (
map_id INT NOT NULL ,
cell_index INT NOT NULL ,
...
PRIMARY KEY (map_id, cell_index)
)
每个映射5,000行很多,但查询应该在数百万行中保持高效,因为主连接索引可以是集群的。如果它太笨重,可以在map_id边界上进行分区。尽管每个地图的行数很多,但这个表格可以很大程度地扩展。
问题在于存储描述哪些单元彼此相邻的数据。单元 - 邻居关系是针对同一表的多对多关系。每张地图也有很多这样的关系。规范化的表可能看起来像这样:
CREATE TABLE map_cell_neighbors (
id INT NOT NULL AUTO INCREMENT ,
map_id INT NOT NULL ,
cell_index INT NOT NULL ,
neighbor_index INT ,
...
INDEX IX_neighbors (map_id, cell_index)
)
此表需要一个永远不会在连接中使用的代理键。此外,此表包含重复条目:如果单元格0是单元格1的邻居,则单元格1始终是单元格0的邻居。我可以消除这些条目,但需要额外的索引空间:
CREATE TABLE map_cell_neighbors (
id INT NOT NULL AUTO INCREMENT ,
map_id INT NOT NULL ,
neighbor1 INT NOT NULL ,
neighbor2 INT NOT NULL ,
...
INDEX IX_neighbor1 (map_id, neighbor1),
INDEX IX_neighbor2 (map_id, neighbor2)
)
我不确定哪一个被认为更“标准化”,因为选项1包含重复的条目(包括复制关系所具有的任何属性),而选项2是一些非常奇怪的数据库设计,只是感觉不规范。这两种选择都不是非常节省空间的。对于10个映射,选项1使用300,000行占用12M的文件空间。选项2是150,000行占用8M的文件空间。在两个表中,索引占用的空间比数据多,考虑到数据应该是每行大约20个字节,但它实际上在磁盘上占用了40-50个字节。
第三个选项根本不会被标准化,但是会非常节省空间和行。它涉及在map_cell中放置一个VARBINARY字段,并在单元格表本身中存储二进制打包的邻居列表。这将需要每个单元24-36个字节,而不是每个关系40-50个字节。它还会减少总行数,并且由于群集主键,对单元格表的查询会非常快。但是,对这些数据执行连接是不可能的。任何递归查询都必须一步一步完成。此外,这只是非常丑陋的数据库设计。
不幸的是,我需要我的应用程序才能很好地扩展,而不是只用50个地图就可以达到SQL瓶颈。除非我能想到别的东西,否则后一种选择可能是唯一真正起作用的选择。在我提出如此卑鄙的想法进行编码之前,我想确保我清楚地看到所有选项。可能还有另一种我没想到的设计模式,或者我预见到的问题并不像它们出现的那么糟糕。无论哪种方式,我都希望得到其他人的意见,然后再深入探讨。
针对此数据的最复杂查询将是路径查找和路径发现。这些将是递归查询,这些查询从特定单元格开始,并通过多次迭代遍历邻居并收集/比较这些单元格的属性。我很确定我不能在SQL中完成所有这些工作,整个过程中可能会有一些应用程序代码。我希望能够执行中等大小的查询,并在可接受的时间内获得结果,以便对用户感觉“响应”,大约一秒钟。总体目标是保持较大的表大小不会导致重复查询或固定深度递归查询花费几秒或更长时间。
答案 0 :(得分:0)
不确定您使用的是哪个数据库,但您似乎正在重新发明已支持空间的数据库已支持的内容。
例如,如果SQL Server是一个选项,您可以将多边形存储为几何类型,使用内置空间索引和符合OGC的方法,如“STContains”,“STCrosses”,“STOverlaps”, “STTouches”。
SQL Server空间索引在将多边形分解为各种b树图层后,还使用细分来索引给定多边形在树索引的给定层上接触的相邻单元格。
还有其他支持空间类型的主流数据库,包括MySQL