我很感激任何人的任何建议:
如何有效地将gps(或任何浮点数)存储在可以索引的varchar字段中。
背景:
我们开发了一个内容管理系统,可以有效地存储任何类型的文件和一组元数据。此文件/元数据存储如下:
file_table metadata_table
---------- --------------
file_id -> file_id (number)
file_name metadata_id (number)
file_location metadata_value (varchar)
...etc
我被要求为地理标记文件提供支持(即将gps坐标存储为元数据)。此外,我们还希望支持具有多个地理标记的文件。
现在据我所知,我有几个选择:
1)将纬度和经度存储在相同的metadata_value varchar中(例如'52.4343242,-1.32324')。
我如何查询此字符串?有什么聪明的我可以使用sql,允许我查询字符串的“组件”?我可以将坐标存储为xml字符串 - 这会有帮助吗?如何有效地编制索引?
2)将纬度和经度存储为 metadata_table 中的单独行。
此解决方案解决了支持更容易查询的问题(以牺牲复杂性和笨重为代价,特别是当我将为每个文件存储多个地理标记时),但是我仍然面临索引问题。
我可以在查询时将varchars转换为浮点数,但是我不确定这是否会忽略我在 metadata_table.metadata_value 上的索引,而是执行表扫描。
3)创建专用浮点字段以存储gps数据。
这是最不可取的选项,因为它违背了设计的范围,为特定元数据添加数据库字段。并非所有文件都会存储gps数据。
任何帮助或建议表示赞赏。
答案 0 :(得分:4)
您可以使用Oracle定位器。 Oracle Spatial的免费子集可以执行各种不同的地理操作和空间数据索引:http://www.oracle.com/technology/products/spatial/index.html
通过使用列类型mdsys.sdo_geometry,您可以在数据库中存储点,云点,线,多边形和3D事物。
答案 1 :(得分:3)
这可以是任何帮助:http://postgis.refractions.net
答案 2 :(得分:3)
虽然您已经使用Oracle标记了这一点,但我认为这对使用MySQL的任何人都很有用:use the spatial extensions to store location data。
答案 3 :(得分:2)
使用专用浮点字段或类型为mdsys.sdo_geometry的列是存储此数据的最佳方法。如果文件没有GPS数据,那些字段将为空,但为什么这应该是一个问题?如果文件可以有多个关联点,则使用详细信息表。
选项1和2是“通用”解决方案。通用数据库解决方案很慢,因为它们更难以索引并且收集统计信息变得更难,因此查询优化器的生活变得更加困难。
使用Cognos(商业智能)等工具通过通用解决方案收集管理信息的报告对您的用户来说更难。
在日期字段中存储日期,在数字字段中存储数字,在地理字段中存储地理信息(mdsys.sdo_geometry)。
这里解释了为什么在数字字段中存储类似“20031603”的日期会减慢速度:http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:77598210939534。
答案 4 :(得分:1)
对于选项1,我可以说:使用Gps eXchange Format (GPX)。这是保存GPS点的标准方法。有标记航点,航迹和兴趣点的选项 尽管如此,查询并不容易。
答案 5 :(得分:1)
编辑:请参阅评论内容不足之处。
要回答您的基本问题,忽略其背后的任何推理,您可以使用function-based indexes。如果你选择#2选项,这应该是直截了当的。
如果你坚持使用#1,你只需添加一些instr / substr voodoo;例如:
select
to_number(
substr(
'52.4343242,-1.32324'
, 1
, instr( '52.4343242,-1.32324', ',' ) - 1
)
) as lattitude
, to_number(
substr(
'52.4343242,-1.32324'
, instr( '52.4343242,-1.32324', ',' ) + 1
)
) as longitude
from dual;
所以你会做类似的事情:
create index lat_long_idx on metadata_table (
to_number(
substr(
metadata_value
, 1
, instr( metadata_value, ',' ) - 1
)
)
, to_number(
substr(
metadata_value
, instr( metadata_value, ',' ) + 1
)
)
);
答案 6 :(得分:1)
通常情况下,如果我有一个通用的表(我并不认为它们没用),我倾向于允许一系列数据类型进行存储,并提供类型。 E.g。
CREATE TABLE MetaDataType (
MetaDataID int IDENTITY(1,1) not null,
MetaDataType varchar(10) not null,
constraint PK_MetaDataType PRIMARY KEY (MetaDataID),
constraint UQ_MetaDataType_TypeCheck UNIQUE (MetaDataID,MetaDataType),
constraint CK_MetaDataType CHECK (MetaDataType in ('INT','CHAR','FLOAT'))
)
然后元数据表看起来像:
CREATE TABLE MetaData (
FileID int not null,
MetaDataID int not null,
MetaDataType varchar(10) not null,
IntValue int null,
CharValue varchar(max) null,
FloatValue float null,
constraint PK_MetaData PRIMARY KEY (FileID,MetaDataID),
constraint FK_MetaData_Files FORIEGN KEY (FileID) references /* File table */,
constraint FK_MetaData_Types FOREIGN KEY (MetaDataID,MetaDataType) references MetaDataTypes (MetaDataID,MetaDataType),
constraint CK_MetaData_ValidTypes ((MetaDataType = 'INT' or IntValue is null) and (MetaDataType = 'CHAR' or CharValue is null) and (MetaDataType = 'FLOAT' or FloatValue is null))
)
重点是1)您为每个Meta数据项存储预期类型,以及2)您在MetaData表中强制执行该操作。