优化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,并且也很好地考虑了位图索引(必须阅读一些相关的信息)。