您的数据的坐标系是什么?而且,最重要的是,您在元数据中设置了什么容限?
其他一些评论:
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 cm 内的一对点 A 和 B 将被返回两次:一次为 (A,B),另一次为 (B,A)。为避免这种情况(并且只返回其中一种情况),请编写如下查询:
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 Enterprise Edition 的许可证并且您的硬件具有适当的容量(内核数),那么并行性可以减少经过的时间。
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 这一事实意味着在测量或基于距离的搜索中使用显式单位将不起作用。因为数据库不知道您的数据在哪个坐标系中,所以它不知道如何确定两个点之间的距离小于设定的 cm 或 m 数。您所能做的就是假设坐标以米为单位。
所以在我上面给出的例子中,替换'DISTANCE=2 UNIT=CM'
为'DISTANCE=0.02'