将GPS位置存储在数据库varchar字段中

时间:2009-03-05 10:15:56

标签: sql database

我很感激任何人的任何建议:

如何有效地将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数据。

任何帮助或建议表示赞赏。

7 个答案:

答案 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表中强制执行该操作。