Sql 在Oracle 11g中使用SDO几何图形创建物化视图时,无法使用ORDER BY
我正在使用Oracle 11g 2.0.1.0,并在客户端使用Spatial和Oracle SQL Developer。我有一个带有主键Sql 在Oracle 11g中使用SDO几何图形创建物化视图时,无法使用ORDER BY,sql,oracle,sorting,oracle11g,oracle-spatial,Sql,Oracle,Sorting,Oracle11g,Oracle Spatial,我正在使用Oracle 11g 2.0.1.0,并在客户端使用Spatial和Oracle SQL Developer。我有一个带有主键ID的表Places,还有一个带有两列的视图坐标:ID引用Places中的一篇文章,以及SDO几何体点 我想使用以下SQL创建物化视图: CREATE MATERIALIZED VIEW PlaceCoordinates NOCACHE NOPARALLEL BUILD IMMEDIATE USING INDEX REFRESH ON DEMAND COMPLE
ID
的表Places
,还有一个带有两列的视图坐标:ID
引用Places
中的一篇文章,以及SDO几何体点
我想使用以下SQL创建物化视图:
CREATE MATERIALIZED VIEW PlaceCoordinates
NOCACHE NOPARALLEL BUILD IMMEDIATE
USING INDEX
REFRESH ON DEMAND COMPLETE
DISABLE QUERY REWRITE AS
SELECT Places.ID, Coordinates.Point
FROM Places
LEFT OUTER JOIN Coordinates ON Places.ID = Coordinates.ID
ORDER BY Places.ID
这给了我一个错误:
ORA-30373:此上下文中不支持对象数据类型
无论我按什么排序(即使它只是像1
这样愚蠢的东西),我都会得到相同的错误。但是,如果我删除orderby
语句,它就可以正常工作。如果我只做一个普通的SELECT
,而不创建物化视图,它也可以很好地进行排序
为什么我不能分类?这个问题有什么解决办法吗 关键是,在物化视图中使用orderby毫无意义
实际上,物化视图只是一个表,当它所基于的表更新时,它会自动更新。但作为一张桌子,就意味着永远无法保证订购。即使初始MV以所需的顺序存储,也不能保证在应用更新后它会保持不变。确保以正确顺序获得结果的唯一方法是在从MV中选择时使用显式顺序BY
您可以在视图(不是物化视图)中包含ORDER BY,并且在使用该视图时将应用该视图:从视图中选择,则不需要任何ORDER BY。但这是一种非常糟糕的做法。这意味着应用程序可能会在不知情的情况下依赖于某个视图提供的某个假定顺序,直到有人决定从视图中删除该顺序,所有的麻烦都会烟消云散
关键是:如果一个应用程序需要一个特定顺序的结果,那么它必须在它发出的选择中这样说,包括一个orderby
也就是说,查看MV定义,它看起来永远不会随着基表(位置和坐标)的更改而更新:您说它是“按需刷新完成”。换句话说,您(或某些自动过程)会定期触发完全刷新。这与创建新表完全相同。您不妨这样做:
CREATE TABLE PlaceCoordinates AS
SELECT Places.ID, Coordinates.Point
FROM Places
LEFT OUTER JOIN Coordinates ON Places.ID = Coordinates.ID;
每次你想刷新PLACECOORDINATES表时(删除旧表后)都要运行它。它将比MV机械更简单、更高效。另一种方法是创建一次表,然后在必要时截断并填充它:
CREATE TABLE PlaceCoordinates (
ID NUMBER PRIMARY KEY,
Point SDO_GEOMETRY
);
及
这使您可以指定ID是主键—这始终是一个好主意。当然,不要忘记在点列上定义适当的空间索引(假设您希望在地图上显示点或查询点)。好的做法是在刷新内容之前先删除该索引,然后再重新创建(MV方法也需要这样做)
无论选择何种方法(如您指定的MV或表格),地点坐标都不会反映地点和坐标表格的实时状态。它只反映上次手动完全刷新MV或重新加载表格时的状态。如果这是可以接受的,那么你们都准备好了
如果希望PLACECOORDINATES更接近其他两个表的状态,而不必完全刷新/重新加载它(例如每分钟一次),则需要定义MV,以便仅从源表中的更改刷新它。这意味着您需要在记录更改的表上创建一个物化视图日志,以便应用于MV。但是,这只会在您指定的时间间隔或手动请求刷新时发生。但合理地说,不超过每分钟。当然不是每秒钟
如果PlaceCoordination必须在发生时反映位置和坐标的所有更改(=实时),那么保证这一点的唯一方法是将其设置为一个表,并在位置和坐标上设置触发器,以便在发生更改时自动将更改应用于这些表中的PlaceCoordination
在这种情况下,您最好直接从基表中读取。当您orderby1
时,您仍然在引用places.ID
,只是。它是否允许您在不使用表格前缀的情况下按ID进行排序?另请参见MOS文档1939208.1,该文档适用于12c,但可能与此相关;或1067173.1。当您查询MV时,您是在订购还是为了避免必须有一个order by
,这不能保证有效?谢谢您的评论。你知道为什么我不能引用Places.ID
?当我明天回去工作时,我将在没有表前缀的情况下进行测试。如果位置引用不起作用,我怀疑它是否会像ID
一样起作用,但也许值得一试。除了我提到的那两份文件之外,恐怕没有。。即使在您查询MV时,它似乎在今天没有订购人的情况下工作,也可能不会有一天。谢谢您的回复。你是对的,MV将按计划更新,并不总是反映表的当前状态,但这对我来说是正确的。我想我会在每次查询MV时,而不是在创建MV时,简单地接受排序的性能影响,这似乎是正确的做法。“这与创建新表完全相同”-除了删除和重新创建表会使引用它的任何内容无效,您必须重新创建授权和索引,任何试图在重建时查看它的东西都会出错。文档还说,您可以在初始创建时按订单,但在刷新时会被忽略,所以不太确定这是什么意思。(并且可以保证视图中的订单在您查询它时总是会被反映出来?)我的意思是
TRUNCATE TABLE PlaceCoordinates;
INSERT INTO PlaceCoordinates (ID, Point)
SELECT Places.ID, Coordinates.Point
FROM Places
LEFT OUTER JOIN Coordinates ON Places.ID = Coordinates.ID;