目前我正在研究一个研究项目,我需要存储时空数据并对其进行有效分析。我在下面给出了确切的要求。
研究正在进行气象数据,所以数据属性是温度,湿度,压力,风速,风向等。我们以前不知道属性的数量,这取决于我们可能需要添加更多的要求属性(具有动态属性和不同数据类型性质的表)。同样,数据从不同的位置,从不同的高度,在一定的持续时间和时间间隔中捕获。
那么,为需求设计架构的最佳方法是什么?我们必须有效地找出关系。
项目的目的不仅是存储数据库,还需要操纵数据。
表格格式的示例数据 -
location | time | height | pressure | temparature | wind-direction | ... L1 | 2011-12-18 08:04:02 | 7 | 1009.6 | 28.3 | east | ... L1 | 2011-12-18 08:04:02 | 15 | 1008.6 | 27.9 | east | ... L1 | 2011-12-18 08:04:02 | 27 | 1007.4 | 27.4 | east | ... L1 | 2011-12-18 08:04:04 | 7 | 1010.2 | 28.4 | north-east | ... L1 | 2011-12-18 08:04:04 | 15 | 1009.4 | 28.2 | north-east | ... L1 | 2011-12-18 08:04:04 | 27 | 1008.9 | 27.6 | north-east | ... L2 | 2011-12-18 08:04:02 | ..... so on
这里我需要为上面的示例数据设计一个模式,其中Location是一个可以使用oracle MDSYS.SDO_GEOMETRY类型实现的空间位置。
约束条件是:
1)在开发期间,属性(表列)的数量是未知的。在运行时,可以添加任何新属性(比方说 - 湿度,折射率等)。所以我们不能设计属性特定的表模式
1.1)对于这种约束,我想使用像 -
这样的模式
tbl_attributes(attr_id_pk,attr_name,attr_type);
tbl_data(loc,time,attr_id_fk,value);
我的设计属性值必须是varchar类型,并且根据需要我想要投射(根本不是一个好主意)
但是,仅使用SQL查询来查找使用此模式的关系数据非常困难。例如,我想找到 -
1.1.1)风向为东,温度在27-28之间时,位置L1的平均压力
1.1.2)压力在15高度处最大的位置
1.2)我也在考虑在运行时编辑表模式,我认为这也不是一个好主意
2)我们将使用一个加载器应用程序,它将根据模式(它可能是什么)来处理这种动态检查。
3)需要有效地检索统计数据,如上面给出的一些例子[1.1。*]。
答案 0 :(得分:3)
当你这么说时,我并不完全确定我理解你的意思
开发期间未知属性(表列)。在 运行时任何新属性(比方说 - 湿度,折射率等) 可以添加。
首先,我认为这并不是随机发生的事情:即当您从现场获得一堆新数据时(导入前),这些数据会有一两个额外的维度。正确的吗?
此外,在这个新的数据批次中你得到“折射率”的事实不会使旧的数据神奇地获得这个维度的适当值。
因此,我会选择经典的Object-to-RDBMS映射:
包含每次测量所存在事物的标题表:即时间和空间,可能是源(即实验室,传感器,提供数据的团队)和自动生成的密钥。
一个或多个详细信息表,其中值被定义为适当的字段。
示例:
标题
location | time | height | source |Key |
L1 | 2011-12-18 08:04:02 | 7 | team-1 | 002020013 |
L1 | 2011-12-18 08:04:02 | 15 | team-1 | 002020017 |
L1 | 2011-12-18 08:04:02 | 27 | Lab-X | 002020018 |
L1 | 2011-12-18 08:04:04 | 7 | Lab-Y | 002020021 |
L1 | 2011-12-18 08:04:04 | 15 | Lab-X | 002020112 |
大气数据(基本)
Key | pressure | temp | wind-dir |
002020013 | 1009.6 | 28.3 | east |
002020017 | 1019.3 | 29.2 | east |
002020018 | 1011.6 | 26.9 | east |
光传感器数据
Key | refractive-ind | albedo | Ultraviolet |
002020017 | 79.6 | .37865 | 7.0E-34 |
002020018 | 67.4 | .85955 | 6.5E-34 |
002020021 | 91.6 | .98494 | 8.1E-34 |
换句话说:每个不同的数据集将使用一个或多个子表(如果需要,您可以“动态”添加),您仍然可以通过标准方法创建查询,您只需加入子表(如果可能) :即如果你想通过Wind Direction和折射率进行分析,你可以 - 但只有当你拥有两个值的数据集时才能通过使用引用键保持这些一致)。
我认为这比使用CSV内部的文本字段或数据blob或使用键值关联更有效。
答案 1 :(得分:1)
我肯定会使用1.2(在运行时编辑表模式),至少开始时。任何足够先进的配置都无法与编程区分开来;不要以为你可以神奇地避免改变你的程序。
不要害怕alter table
。是的,前期成本更高 - 您可能需要一个流程(而不仅仅是程序)来确保您的架构保持干净。并且存在一些潜在的锁定问题(具有解决方案)。 但如果你做得对,你只需为每次改变支付一次价格。
使用完全通用的解决方案,您将为每个查询支付一小笔费用。您的查询将变得复杂,缓慢,丑陋,并且更有可能失败。您永远不能编写select avg(value) ...
之类的查询,它可能会也可能不会起作用,具体取决于数据的访问方式。您可以使用PL / SQL函数来捕获异常,或使用内联视图和提示来强制使用特定的访问模式。无论哪种方式,您的查询都更复杂,速度更慢,您必须确保每个人在使用数据之前都能理解这些问题。
使用通用解决方案,优化器会很糟糕,因为它对您的数据一无所知。 Oracle无法预测where attr_name = 'temperature' and is_number(value) = 28.4
将返回多少行。但它可以对where temperature = 28.4
做出很好的猜测。使用通用列可能会有更多糟糕的计划(即慢查询)。
答案 2 :(得分:1)
感谢您的快速反应和良好的指导。我从两个答案中得到了一些概念,并决定使用混合模型。我不知道我是否在写路径中。我想要对模型发表评论。下面我将用MySQL代码片段描述完整的概念模型。
CREATE PROCEDURE `buildModel`()
BEGIN
DECLARE done INT DEFAULT FALSE;
DECLARE fid INTEGER;
DECLARE fname VARCHAR(45);
DECLARE ftype VARCHAR(45);
DECLARE cur_fatures CURSOR FOR SELECT `featureid`, `name`, `type` FROM `metfeatures`;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
SET @viewAlias = 'v_';
SET @metRelView = "metrelview";
SET @stmtCols = "";
SET @stmtJoin = "";
START TRANSACTION;
OPEN cur_fatures;
read_loop: LOOP
FETCH cur_fatures INTO fid, fname, ftype;
IF done THEN
LEAVE read_loop;
END IF;
IF fname IS NOT NULL THEN
SET @featureView = CONCAT(@viewAlias, LOWER(fname));
IF ftype = 'float' THEN
SET @featureCastStr = "`value`+0.0";
ELSEIF ftype = 'int' THEN
SET @featureCastStr = "CAST(`value` AS SIGNED)";
ELSE
SET @featureCastStr = "`value`";
END IF;
SET @stmtDeleteView = CONCAT("DROP VIEW IF EXISTS `", @featureView, "`");
SET @stmtCreateView = CONCAT("CREATE VIEW `", @featureView, "` AS SELECT le.`loceventid` AS loceventid, le.`locid`, le.`rectime`, le.`height`, ", @featureCastStr, " AS value FROM `metlocevent` le JOIN `metstore` ms ON (le.`loceventid`=ms.`loceventid`) WHERE ms.`featureid`=", fid);
PREPARE stmt FROM @stmtDeleteView;
EXECUTE stmt;
PREPARE stmt FROM @stmtCreateView;
EXECUTE stmt;
SET @stmtCols = CONCAT(@stmtCols, ", ", @featureView, ".`value` AS ", @featureView);
SET @stmtJoin = CONCAT(@stmtJoin, " ", "LEFT JOIN ", @featureView, " ON (le.`loceventid`=", @featureView,".`loceventid`)");
END IF;
END LOOP;
SET @stmtDeleteView = CONCAT("DROP VIEW IF EXISTS `", @metRelView, "`");
SET @stmtCreateView = CONCAT("CREATE VIEW `", @metRelView, "` AS SELECT le.`loceventid`, le.`locid`, le.`rectime`, le.`height`", @stmtCols, " FROM `metlocevent` le", @stmtJoin);
PREPARE stmt FROM @stmtDeleteView;
EXECUTE stmt;
PREPARE stmt FROM @stmtCreateView;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
CLOSE cur_fatures;
COMMIT;
END;
N.B。 - 我尝试使用功能表中的任何事件调用该过程,以便每个事情都应该自动化。但由于MySQL不支持动态查询功能或触发器,我无法自动执行
在我最终确定为可接受的模型之前,我也想要批评,我不是DBA所以,如果你可以帮助我如何提高模型的性能对我有用。
答案 3 :(得分:1)
这听起来像是一项家庭作业,其基本主题是:放弃严格的正常形式设计原则的用例。
解决这个难题的方法是开发一个三阶段解决方案。阶段1是使用灵活的AttributeType,AttributeValue方法的运行时适应性,以便可以以准结构化的方式捕获快速传入的数据并将其暂时放置在某处。第2阶段涉及对运行时数据的分析,以查看必须使用其他列和验证表扩展模型的位置以适应任何新属性。第3阶段是将尚未经过排序的数据导入到修订后的模型中,该模型从不放松其严格的数据类型和声明性参照完整性约束。
正如他们所说:生活,朋友,是一种权衡。