Oracle Spatial - SDO_BUFFER 不起作用?
Oracle Spatial - SDO_BUFFER does not work?
我有一个 table,它有 SDO_Geometries,我查询所有几何图形以找到它们的起点和终点,然后我将这些点插入另一个名为 ORAHAN 的 table。现在我的主要目的是对于 orahan 中的每个点,我必须在为点提供 2 cm 缓冲区时发现它是否与 orahan 中的另一个点相交。
因此,我使用 Relate 和 Bufer 函数编写了一些 pl sql,但是当我检查 Map Info 中的一些记录时,我看到在其自身 1 厘米区域内有一些点,但在称为 ORAHANCROSSES 的交叉点 table 中没有记录。
是我用错了这些功能还是怎么的?
注意:我使用的是 Oracle 数据库 11g 企业版 11.2.0.1.0 版 - 64 位生产版和
PL/SQL 版本 11.2.0.1.0 - 和 SDO_PACKAGE
ORAHAN 有大约 40 万条记录。(点和其他列。)
declare
BEGIN
for curs in (select * from ORAHAN t) loop
for curs2 in (select *
from ORAHAN t2
where SDO_RELATE(t2.geoloc,SDO_GEOM.SDO_BUFFER(curs.geoloc,0.02,0.5) ,
'mask=ANYINTERACT') = 'TRUE'
and t2.mi_prinx <> curs.mi_prinx) loop
Insert INTO ORAHANCROSSES
values
(curs.Mip, curs.Startmi, curs2.Mip, curs2.Startmi);
commit;
end loop;
end loop;
END;
这是 MapInfo 地图图像,显示了彼此接近约 1 厘米的 3 个点。但是在orahancrosses中没有匹配这3个的记录。
注:0,00001000km等于1cm
奥拉汉元数据:
select * from user_sdo_geom_metadata where table_name = 'ORAHAN';
和暗信息:
你的数据坐标系是什么?而且,最重要的是,您在元数据中设置了什么 容差?
其他一些评论:
1) 不要使用与缓冲区关联的方法。只需使用距离内的方法。
2) 对于这种查询,您不需要 PL/SQL 循环,只需使用简单的 CTAS:
create table orahancrosses as
select c1.mip mip_1, c1.startmi startmi_1, c2.mip mip_2, c2.startmi startmi_2
from orahan c1, orahan c2
where sdo_within_distance (c2.geoloc, c1.geoloc, 'distance=2 unit=cm') = 'TRUE'
and c2.mi_prinx <> c1.mi_prinx;
3) 正如所写,2 厘米以内的一对点 A 和 B 将被 return 编辑两次:一次作为 (A,B),另一次作为 (B,A)。为了避免这种情况(并且只有 return 一种情况),然后像这样编写查询:
create table orahancrosses as
select c1.mip mip_1, c1.startmi startmi_1, c2.mip mip_2, c2.startmi startmi_2
from orahan c1, orahan c2
where sdo_within_distance (c2.geoloc, c1.geoloc, 'distance=2 unit=cm') = 'TRUE'
and c1.rowid < c2.rowid;
3) 处理你提到的点数 (400000+) 应该 运行 更好地使用 SDO_JOIN 技术,像这样:
create table orahancrosses as
select c1.mip mip_1, c1.startmi startmi_1, c2.mip mip_2, c2.startmi startmi_2
from table (
sdo_join (
'ORAHAN','GEOLOC',
'ORAHAN','GEOLOC',
'DISTANCE=2 UNIT=CM'
)
) j,
orahan c1,
orahan c2
where j.rowid1 < j.rowid2
and c1.rowid = j.rowid1
and c2.rowid = j.rowid2;
这可能仍需要时间来处理 - 取决于您的数据库服务器的容量。如果您是 Oracle 企业版的许可证并且您的硬件具有适当的容量(内核数),那么并行性可以减少运行时间。
4) 你说你用的是Oracle 11g。什么确切的版本?版本 11.2.0.4 是 11gR2 的终端版本。不再支持任何旧版本。到现在为止,您实际上应该在 12cR1 (12.1.0.2) 上。在您的案例中,12.1.0.2 的主要优势是 Vector Performance Accelerator 功能,它可以加速许多空间函数和运算符(仅当您拥有适当的 Oracle Spatial 许可证时 - 它不适用于免费的 Oracle Locator 功能)。
======================================
使用你例子中的两点。让我们计算距离:
select sdo_geom.sdo_distance(
sdo_geometry (2001,null,sdo_point_type(521554.782174622,4230983.08336913,null),null,null),
sdo_geometry (2001,null,sdo_point_type(521554.782174622,4230983.07336716,null),null,null),
0.005
) distance
from dual;
DISTANCE
----------
.01000197
1 row selected.
注意我没有指定任何 SRID。假设坐标用米表示,它们之间的距离确实是1厘米多一点。
======================================
正如您所注意到的,您的原始语法不起作用的原因是您为 SDO_BUFFER() 调用指定的容差。您将其作为 0.5 (=50cm) 传递以生成半径为 0.02 (2cm) 的缓冲区。效果是产生的缓冲区有效地溶解到点本身中。
例如公差为 0.5:
select sdo_geom.sdo_buffer(sdo_geometry (2001,null,sdo_point_type(521554.782174622,4230983.08336913,null),null,null),0.02,0.5) from dual;
产生:
SDO_GEOMETRY(2001, NULL, SDO_POINT_TYPE(521554.782, 4230983.08, NULL), NULL, NULL)
公差为 0.005:
select sdo_geom.sdo_buffer(sdo_geometry (2001,null,sdo_point_type(521554.782174622,4230983.08336913,null),null,null),0.02,0.005) from dual;
您获得了正确的缓冲区:
SDO_GEOMETRY(2003, NULL, NULL, SDO_ELEM_INFO_ARRAY(1, 1003, 2), SDO_ORDINATE_ARRAY(521554.782, 4230983.06, 521554.802, 4230983.08, 521554.782, 4230983.1, 521554.762, 4230983.08, 521554.782, 4230983.06))
现在非常接近的点与该缓冲区匹配:
select sdo_geom.relate(
sdo_geom.sdo_buffer(sdo_geometry (2001,null,sdo_point_type(521554.782174622,4230983.08336913,null),null,null),0.02,0.005),
'determine',
sdo_geometry (2001,null,sdo_point_type(521554.782174622,4230983.07336716,null),null,null),
0.005
) relation
from dual;
RELATION
-------------------------
CONTAINS
1 row selected.
======================================
现在,您的数据没有正确的显式 SRID 意味着在测量或基于距离的搜索中使用显式单位将不起作用。因为数据库不知道你的数据在什么坐标系中,所以它不知道如何确定两点相距小于设定的厘米数或米数。您所能做的就是假设坐标以米为单位。
所以在我上面给出的示例中,将 'DISTANCE=2 UNIT=CM'
替换为 'DISTANCE=0.02'
我有一个 table,它有 SDO_Geometries,我查询所有几何图形以找到它们的起点和终点,然后我将这些点插入另一个名为 ORAHAN 的 table。现在我的主要目的是对于 orahan 中的每个点,我必须在为点提供 2 cm 缓冲区时发现它是否与 orahan 中的另一个点相交。 因此,我使用 Relate 和 Bufer 函数编写了一些 pl sql,但是当我检查 Map Info 中的一些记录时,我看到在其自身 1 厘米区域内有一些点,但在称为 ORAHANCROSSES 的交叉点 table 中没有记录。 是我用错了这些功能还是怎么的?
注意:我使用的是 Oracle 数据库 11g 企业版 11.2.0.1.0 版 - 64 位生产版和 PL/SQL 版本 11.2.0.1.0 - 和 SDO_PACKAGE
ORAHAN 有大约 40 万条记录。(点和其他列。)
declare
BEGIN
for curs in (select * from ORAHAN t) loop
for curs2 in (select *
from ORAHAN t2
where SDO_RELATE(t2.geoloc,SDO_GEOM.SDO_BUFFER(curs.geoloc,0.02,0.5) ,
'mask=ANYINTERACT') = 'TRUE'
and t2.mi_prinx <> curs.mi_prinx) loop
Insert INTO ORAHANCROSSES
values
(curs.Mip, curs.Startmi, curs2.Mip, curs2.Startmi);
commit;
end loop;
end loop;
END;
这是 MapInfo 地图图像,显示了彼此接近约 1 厘米的 3 个点。但是在orahancrosses中没有匹配这3个的记录。
注:0,00001000km等于1cm
奥拉汉元数据:
select * from user_sdo_geom_metadata where table_name = 'ORAHAN';
和暗信息:
你的数据坐标系是什么?而且,最重要的是,您在元数据中设置了什么 容差?
其他一些评论:
1) 不要使用与缓冲区关联的方法。只需使用距离内的方法。
2) 对于这种查询,您不需要 PL/SQL 循环,只需使用简单的 CTAS:
create table orahancrosses as
select c1.mip mip_1, c1.startmi startmi_1, c2.mip mip_2, c2.startmi startmi_2
from orahan c1, orahan c2
where sdo_within_distance (c2.geoloc, c1.geoloc, 'distance=2 unit=cm') = 'TRUE'
and c2.mi_prinx <> c1.mi_prinx;
3) 正如所写,2 厘米以内的一对点 A 和 B 将被 return 编辑两次:一次作为 (A,B),另一次作为 (B,A)。为了避免这种情况(并且只有 return 一种情况),然后像这样编写查询:
create table orahancrosses as
select c1.mip mip_1, c1.startmi startmi_1, c2.mip mip_2, c2.startmi startmi_2
from orahan c1, orahan c2
where sdo_within_distance (c2.geoloc, c1.geoloc, 'distance=2 unit=cm') = 'TRUE'
and c1.rowid < c2.rowid;
3) 处理你提到的点数 (400000+) 应该 运行 更好地使用 SDO_JOIN 技术,像这样:
create table orahancrosses as
select c1.mip mip_1, c1.startmi startmi_1, c2.mip mip_2, c2.startmi startmi_2
from table (
sdo_join (
'ORAHAN','GEOLOC',
'ORAHAN','GEOLOC',
'DISTANCE=2 UNIT=CM'
)
) j,
orahan c1,
orahan c2
where j.rowid1 < j.rowid2
and c1.rowid = j.rowid1
and c2.rowid = j.rowid2;
这可能仍需要时间来处理 - 取决于您的数据库服务器的容量。如果您是 Oracle 企业版的许可证并且您的硬件具有适当的容量(内核数),那么并行性可以减少运行时间。
4) 你说你用的是Oracle 11g。什么确切的版本?版本 11.2.0.4 是 11gR2 的终端版本。不再支持任何旧版本。到现在为止,您实际上应该在 12cR1 (12.1.0.2) 上。在您的案例中,12.1.0.2 的主要优势是 Vector Performance Accelerator 功能,它可以加速许多空间函数和运算符(仅当您拥有适当的 Oracle Spatial 许可证时 - 它不适用于免费的 Oracle Locator 功能)。
======================================
使用你例子中的两点。让我们计算距离:
select sdo_geom.sdo_distance(
sdo_geometry (2001,null,sdo_point_type(521554.782174622,4230983.08336913,null),null,null),
sdo_geometry (2001,null,sdo_point_type(521554.782174622,4230983.07336716,null),null,null),
0.005
) distance
from dual;
DISTANCE
----------
.01000197
1 row selected.
注意我没有指定任何 SRID。假设坐标用米表示,它们之间的距离确实是1厘米多一点。
======================================
正如您所注意到的,您的原始语法不起作用的原因是您为 SDO_BUFFER() 调用指定的容差。您将其作为 0.5 (=50cm) 传递以生成半径为 0.02 (2cm) 的缓冲区。效果是产生的缓冲区有效地溶解到点本身中。
例如公差为 0.5:
select sdo_geom.sdo_buffer(sdo_geometry (2001,null,sdo_point_type(521554.782174622,4230983.08336913,null),null,null),0.02,0.5) from dual;
产生:
SDO_GEOMETRY(2001, NULL, SDO_POINT_TYPE(521554.782, 4230983.08, NULL), NULL, NULL)
公差为 0.005:
select sdo_geom.sdo_buffer(sdo_geometry (2001,null,sdo_point_type(521554.782174622,4230983.08336913,null),null,null),0.02,0.005) from dual;
您获得了正确的缓冲区:
SDO_GEOMETRY(2003, NULL, NULL, SDO_ELEM_INFO_ARRAY(1, 1003, 2), SDO_ORDINATE_ARRAY(521554.782, 4230983.06, 521554.802, 4230983.08, 521554.782, 4230983.1, 521554.762, 4230983.08, 521554.782, 4230983.06))
现在非常接近的点与该缓冲区匹配:
select sdo_geom.relate(
sdo_geom.sdo_buffer(sdo_geometry (2001,null,sdo_point_type(521554.782174622,4230983.08336913,null),null,null),0.02,0.005),
'determine',
sdo_geometry (2001,null,sdo_point_type(521554.782174622,4230983.07336716,null),null,null),
0.005
) relation
from dual;
RELATION
-------------------------
CONTAINS
1 row selected.
======================================
现在,您的数据没有正确的显式 SRID 意味着在测量或基于距离的搜索中使用显式单位将不起作用。因为数据库不知道你的数据在什么坐标系中,所以它不知道如何确定两点相距小于设定的厘米数或米数。您所能做的就是假设坐标以米为单位。
所以在我上面给出的示例中,将 'DISTANCE=2 UNIT=CM'
替换为 'DISTANCE=0.02'