6

我在客户端上使用带有 Spatial 和 Oracle SQL Developer 的 Oracle 11g 2.0.1.0。我有一个Places带有主键的表和一个带有 tw 列ID的视图:引用中的帖子和 SDO 几何。CoordinatesIDPlacesPoint

我想使用以下 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)我都会得到同样的错误。但是,如果我删除该ORDER BY语句,它就可以正常工作。SELECT如果我只是做一个普通的而不创建物化视图,它也适用于排序。

为什么我不能排序?反正有这个问题吗?

4

1 回答 1

9

关键是物化视图中的 ORDER BY 没有意义。

在幕后,物化视图实际上只是一个表,当它所基于的表被更新时,它会自动更新。但作为一张桌子意味着永远无法保证订购。即使初始 MV 以所需的顺序存储,也不能保证在应用更新后它会保持不变。确保以正确顺序获得结果的唯一方法是在从 MV 中进行选择时使用明确的 ORDER BY。

您可以将 ORDER BY 包含到视图(不是物化视图)中,并且在您使用该视图时应用:从视图中选择然后不需要任何 ORDER BY。但这是一个非常糟糕的做法。这意味着应用程序可能会在不知不觉中依赖于视图提供的一些假定顺序——直到有人决定从视图中删除 ORDER BY 并且所有地狱都崩溃了。

关键是:如果一个应用程序需要一个特定顺序的结果,那么它必须在它发出的 SELECT 中这样说,包括一个 ORDER BY。

也就是说,查看您的 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
);

TRUNCATE TABLE PlaceCoordinates;
INSERT INTO PlaceCoordinates (ID, Point)
SELECT Places.ID, Coordinates.Point
FROM Places
LEFT OUTER JOIN Coordinates ON Places.ID = Coordinates.ID;

这使您可以指定 ID 是主键 - 总是一个好主意。当然,不要忘记在 POINT 列上定义正确的空间索引(假设您想在地图上显示点或查询它们)。好的做法是在刷新内容之前先删除该索引,然后再重新创建它(对于 MV 方法,您也需要这样做)。

无论选择何种方法(指定的 MV 或表),PLACECOORDINATES 都不会反映 PLACES 和 COORDINATES 表的实时状态。它只会反映您上次手动完全刷新 MV 或重新加载表时的状态。如果这是可以接受的,那么你就准备好了。

如果您希望 PLACECOORDINATES 更接近其他两个表的状态,而不必完全刷新/重新加载它,比如每分钟,那么您需要定义 MV,以便仅从源表中的更改中刷新它。这意味着您需要在将记录更改以应用于 MV 的那些表上使用 MATERIALIZED VIEW LOG。但是,这只会在您指定的时间间隔或您手动请求刷新时发生。但合理地不超过每分钟。当然不是每一秒。

如果 PLACESCOORDINATES 必须反映 PLACES 和 COORDINATES 中发生的所有更改(=“实时”),那么保证这一点的唯一方法是使其成为一个表,并在 PLACES 和 COORDINATES 上有触发器自动将更改应用于 PLACESCOORDINATES 上的这些表当它们发生时。

也许在这种情况下,您最好直接从基表中读取。

于 2015-07-15T17:44:27.203 回答