Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/oracle/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
优化SQL查询:查找在地理位置上相互关联但没有关联的项_Sql_Oracle - Fatal编程技术网

优化SQL查询:查找在地理位置上相互关联但没有关联的项

优化SQL查询:查找在地理位置上相互关联但没有关联的项,sql,oracle,Sql,Oracle,我有一个非常具体的问题,我不完全确定这是否是提出这个问题的正确地点。我们从客户机获得提交给我们的数据,为了验证数据的质量,我们运行一组查询来检查数据的一致性 在我们的数据模型中,我们有路由(线)和结构(点),当结构位于路由上时,应该存在链接(在另一个表中)。为了验证这一点,我运行以下查询: select s.id as id, r.id as unconnected_route_id from structure s, route r WHERE s.batc

我有一个非常具体的问题,我不完全确定这是否是提出这个问题的正确地点。我们从客户机获得提交给我们的数据,为了验证数据的质量,我们运行一组查询来检查数据的一致性

在我们的数据模型中,我们有路由(线)和结构(点),当结构位于路由上时,应该存在链接(在另一个表中)。为了验证这一点,我运行以下查询:

      select s.id as id, r.id as unconnected_route_id
      from structure s, route r
      WHERE s.batch_number = '%{batch_number}'
        and r.batch_number = '%{batch_number}'
        and SDO_ANYINTERACT(s.geometry, r.geometry) = 'TRUE'
        and not exists (
          select * from feature_connectivity
          where feature_id = r.id and feature_code=1001
            and node1_feature_code = 1003
            and (node1_id = s.id or node2_id = s.id)
        )
这在测试阶段工作得很好,但现在我们正在比较一组约25000个结构和一组约25000个路由,这实际上需要几个小时。所有的索引都准备好了,我向dba询问了我们如何改进,但我们无法想出一些办法

[更新:添加解释计划和数据模型/索引]

数据模型:

  • ROUTE和STRUCTURE都有一个ID、批次号、几何字段(以及一组其他不相关的列)
  • 这两个表都有一个关于批号的索引和一个关于几何体的空间索引
索引:

CREATE INDEX "INFRA"."ROUTE_IX01" ON "INFRA"."ROUTE" ("BATCH_NUMBER") 
CREATE INDEX "INFRA"."ROUTE_SX01" ON "INFRA"."ROUTE" ("GEOMETRY") INDEXTYPE IS "MDSYS"."SPATIAL_INDEX"  PARAMETERS ('layer_gtype=curve');

CREATE INDEX "INFRA"."STRUCTURE_IX01" ON "INFRA"."STRUCTURE" ("BATCH_NUMBER") 
CREATE INDEX "INFRA"."STRUCTURE_SX01" ON "INFRA"."STRUCTURE" ("GEOMETRY") INDEXTYPE IS "MDSYS"."SPATIAL_INDEX"  PARAMETERS ('layer_gtype=point');
CREATE INDEX "COMMON"."FEATURE_CONNECTIVITY_IX01" ON "COMMON"."FEATURE_CONNECTIVITY ("FEATURE_ID", "FEATURE_CODE") 
CREATE INDEX "COMMON"."FEATURE_CONNECTIVITY_IX02" ON "COMMON"."FEATURE_CONNECTIVITY ("NODE1_ID", "NODE1_FEATURE_CODE") 
CREATE INDEX "COMMON"."FEATURE_CONNECTIVITY_IX03" ON "COMMON"."FEATURE_CONNECTIVITY ("NODE2_ID", "NODE2_FEATURE_CODE") 
CREATE INDEX "COMMON"."FEATURE_CONNECTIVITY_IX04" ON "COMMON"."FEATURE_CONNECTIVITY" ("BATCH_NUMBER") 
create unique index FEATURE_CONNECTIVITY_IX05 on FEATURE_CONNECTIVITY (FEATURE_ID, FEATURE_CODE, NODE1_ID, NODE1_FEATURE_CODE, NODE2_ID, NODE2_FEATURE_CODE)
连接的功能有点不同:

FEATURE_ID, FEATURE_CODE, NODE1_ID, NODE1_FEATURE_CODE, NODE2_ID, NODE2_FEATURE_CODE 
具有以下索引:

CREATE INDEX "INFRA"."ROUTE_IX01" ON "INFRA"."ROUTE" ("BATCH_NUMBER") 
CREATE INDEX "INFRA"."ROUTE_SX01" ON "INFRA"."ROUTE" ("GEOMETRY") INDEXTYPE IS "MDSYS"."SPATIAL_INDEX"  PARAMETERS ('layer_gtype=curve');

CREATE INDEX "INFRA"."STRUCTURE_IX01" ON "INFRA"."STRUCTURE" ("BATCH_NUMBER") 
CREATE INDEX "INFRA"."STRUCTURE_SX01" ON "INFRA"."STRUCTURE" ("GEOMETRY") INDEXTYPE IS "MDSYS"."SPATIAL_INDEX"  PARAMETERS ('layer_gtype=point');
CREATE INDEX "COMMON"."FEATURE_CONNECTIVITY_IX01" ON "COMMON"."FEATURE_CONNECTIVITY ("FEATURE_ID", "FEATURE_CODE") 
CREATE INDEX "COMMON"."FEATURE_CONNECTIVITY_IX02" ON "COMMON"."FEATURE_CONNECTIVITY ("NODE1_ID", "NODE1_FEATURE_CODE") 
CREATE INDEX "COMMON"."FEATURE_CONNECTIVITY_IX03" ON "COMMON"."FEATURE_CONNECTIVITY ("NODE2_ID", "NODE2_FEATURE_CODE") 
CREATE INDEX "COMMON"."FEATURE_CONNECTIVITY_IX04" ON "COMMON"."FEATURE_CONNECTIVITY" ("BATCH_NUMBER") 
create unique index FEATURE_CONNECTIVITY_IX05 on FEATURE_CONNECTIVITY (FEATURE_ID, FEATURE_CODE, NODE1_ID, NODE1_FEATURE_CODE, NODE2_ID, NODE2_FEATURE_CODE)
查询的解释计划如下:

select s.id as id, r.id as unconnected_route_id
  from structure s, route r
  WHERE s.batch_number = '202'
    and r.batch_number = '202'
    and SDO_ANYINTERACT(s.geometry, r.geometry) = 'TRUE'
    and SDO_INSIDE(r.geometry,
        SDO_GEOMETRY(2003, 31370, NULL,
          SDO_ELEM_INFO_ARRAY(1,1003,3),
          SDO_ORDINATE_ARRAY(161481.2819, 204758.7507, 181858.4903, 230979.198 ))
        ) = 'TRUE'
    and not exists (
      select * from feature_connectivity
      where feature_id = r.id and feature_code=1001
        and node1_feature_code = 1003
        and (node1_id = s.id or node2_id = s.id)
    )


是否有任何机构对我们如何改进这一点有任何建议

尝试强制Oracle使用嵌套循环而不是哈希联接,如下所示:

select /*+ USE_NL(s r)*/s.id as id, r.id as unconnected_route_id
      from structure s, route r
      WHERE s.batch_number = '%{batch_number}'
        and r.batch_number = '%{batch_number}'
        and SDO_ANYINTERACT(s.geometry, r.geometry) = 'TRUE'
        and not exists (
          select /*+ NL_AJ(feature_connectivity)*/ * from feature_connectivity
          where feature_id = r.id and feature_code=1001
            and node1_feature_code = 1003
            and (node1_id = s.id or node2_id = s.id)
        )
当服务器的缓冲区中没有足够的空间时,哈希连接可能会非常慢。在这种情况下,它会先将数据写入光盘,然后再读取,而文件的读写速度总是很慢。
如果这不起作用,请提供您的表的结构,这可能会有所帮助。

我不太擅长阅读解释计划,但我有一个评论(在dba.stackexchange.com上——我不得不删除这个问题,因为显然不允许您在两个站点上发布),那就是空间索引没有得到最佳使用

第一次尝试:添加边界框 在设计拆分工作的方法时,我想使用边界框将查询拆分为4个象限,因此我计算了边界框,并首先尝试添加边界框,这对我的解释计划产生了奇迹般的效果。因此,我的问题如下:

select s.id as id, r.id as unconnected_route_id
  from structure s, route r
  WHERE s.batch_number = '202'
    and r.batch_number = '202'
    and SDO_ANYINTERACT(s.geometry, r.geometry) = 'TRUE'
    and SDO_INSIDE(r.geometry,
        SDO_GEOMETRY(2003, 31370, NULL,
          SDO_ELEM_INFO_ARRAY(1,1003,3),
          SDO_ORDINATE_ARRAY(161481.2819, 204758.7507, 181858.4903, 230979.198 ))
        ) = 'TRUE'
    and not exists (
      select * from feature_connectivity
      where feature_id = r.id and feature_code=1001
        and node1_feature_code = 1003
        and (node1_id = s.id or node2_id = s.id)
    )
然后我解释计划的总成本下降到14081:

这已经很神奇了,而且边界框足够大,可以容纳所有东西,所以我有点困惑Oracle本身没有正确处理它。此外,如果我想/需要的话,它将允许我稍后将查询分割成象限

第二次尝试:使用SDO_连接 但后来我们的dba有了一个好主意:使用SDO_JOIN构建一个临时表。我已经用这种方法寻找双打,但坦率地说,我并没有真正理解它。其次,他使用了
减号
,而不是
不存在的

因此,他提出的问题是:

        select r.id              route_id
        ,      s.id              struct_id
        from   route     r
        ,      structure s
        ,      table(sdo_join('route','geometry','structure','geometry','mask=ANYINTERACT')) j
        where  r.rowid = j.rowid1
        and    s.rowid = j.rowid2
        and    r.batch_number = s.batch_number
        and    r.batch_number = '202'
        minus
        ( select feature_id
          ,      node1_id
          from   common.feature_connectivity
          where  batch_number = '202'
          union all
          select feature_id
          ,      node2_id
          from   common.feature_connectivity
          where  batch_number = '202')
      ) results
      where results.struct_id = s.id and results.route_id = r.id
奇怪的是解释计划比原计划差3倍,但执行速度很快:)太奇怪了:不信任解释计划

解释计划如下所示:


最后一个查询是我们现在使用的查询,执行时间从+24小时下降到不到一分钟。

尝试将
SDO\u ANYINTERACT
创建为一个表,而不是一个函数。然后连接结构和到该表的路由就可以有效了。@Franek SDO_ANYINTERACT是一个标准的Oracle Spatial运算符,请参阅。在这种情况下,毫无疑问;)。感谢您对我的建议的宽容回应…哇,太棒了,在一个小测试集上,这将性能从90秒提高到15秒!!!!现在,在大型集合上尝试(耗时26小时…@nathanvda它可能是Oracle cache:)如果第一次运行查询,它会缓存结果,当第二次运行查询时,它不会第二次计算结果,而是从缓存中获取已计算的结果。请在更大的集合上运行后共享结果,我很好奇嵌套循环是否真的有用。谢谢aaahbummer:查询运行了几个小时,我自己无法在该数据库上运行“解释计划”,所以我已经询问了dba。显然oracle已经使用嵌套循环,解释计划对于我的原始查询和您的查询是相同的,所以我假设它不会有什么不同:(对不起!请提供您的表结构?添加+索引。如果您有更多问题,请告诉我。哦,我在上面发表了评论,没有看到您自己的答案,对不起:)但我的建议是正确的——问题在于索引。现在,完全扫描速度很快,但如果您的数据将比现在大得多,则可能需要使用索引。Tom Kyte的《Oracle数据库体系结构专家》一书可能会给你很多答案。很抱歉又耽搁了!嗯,也许是关于索引的一个好提示。我没有首先得到它,但最后一个查询不再使用索引。我猜SDO_连接当然会完成所有工作。我的本地数据库(在我的开发机器上)比我们客户机的服务器快得多。因此,+25H查询在我的机器上使用了100SEC,并且也很好地考虑了位图索引(必须阅读一些相关的信息)。