您无法避免笛卡尔积;但是,您可以提供额外的限制,以便在评估坐标之间的确切距离并执行连接之前过滤掉坐标值之间的明显差异。
您正在尝试查看一个坐标是否在距离另一个坐标 290 个单位的半径内。如果值在这个圆圈内,那么它也在圆圈周围的边界框内;这可能允许您在 x 和 y 坐标上使用索引。
您还可以通过两边平方来摆脱JOIN中的(昂贵的)平方根运算;但是,这可能不会节省很多,因为您仍然需要对匹配的行执行平方根。
create table table2 as
select t.tab_key,
t.x,
t.y,
t.val,
s.val val2,
sqrt(power(t.x - s.x, 2) + power(t.y - s.y, 2)) d
from table1 t
join table1 s
on ( s.val is not null
and s.tab_key != t.tab_key
AND t.x BETWEEN s.x - 290 AND s.x + 290
AND t.y BETWEEN s.y - 290 AND s.y + 290
and power(t.x - s.x, 2) + power(t.y - s.y, 2) <= power(290, 2)
);
所以:
CREATE INDEX table1__tk_v_x_y_idx ON table1( tab_key, val, x, y );
然后:
EXPLAIN PLAN FOR
select t.tab_key,
t.x,
t.y,
t.val,
s.val val2,
sqrt(power(t.x - s.x, 2) + power(t.y - s.y, 2)) d
from table1 t
join table1 s
on ( s.val is not null
and s.tab_key != t.tab_key
AND t.x BETWEEN s.x - 290 AND s.x + 290
AND t.y BETWEEN s.y - 290 AND s.y + 290
and power(t.x - s.x, 2) + power(t.y - s.y, 2) <= power(290, 2)
);
SELECT PLAN_TABLE_OUTPUT FROM TABLE(DBMS_XPLAN.DISPLAY());
给出输出:
|计划表输出 |
| :------------------------------------------------- ------------------------------------------ |
|计划哈希值:2623360073 |
| |
| -------------------------------------------------- ------------------------------------------ |
| |身份证 |操作 |姓名 |行 |字节 |成本 (%CPU)|时间 | |
| -------------------------------------------------- ------------------------------------------ |
| | 0 |选择声明 | | 1 | 104 | 4 (50)| 00:00:01 | |
| | 1 |合并加入 | | 1 | 104 | 4 (50)| 00:00:01 | |
| | 2 |排序加入 | | 5 | 260 | 2 (50)| 00:00:01 | |
| | 3 |索引全扫描 |表 1__TK_V_X_Y_IDX | 5 | 260 | 1 (0)| 00:00:01 | |
| |* 4 |过滤器 | | | | | | |
| |* 5 |排序加入 | | 5 | 260 | 2 (50)| 00:00:01 | |
| |* 6 |索引全扫描|表 1__TK_V_X_Y_IDX | 5 | 260 | 1 (0)| 00:00:01 | |
| -------------------------------------------------- ------------------------------------------ |
| |
|谓词信息(由操作 id 标识):|
| -------------------------------------------------- - |
| |
| 4 - 过滤器("S"."TAB_KEY""T"."TAB_KEY" AND "T"."X"="S"."Y"-290 AND "T"."Y"=“S”。“X”-290)|
|过滤器(INTERNAL_FUNCTION("T"."X")>="S"."X"-290) |
| 6 - 过滤器(“S”。“VAL”不为空)|
| |
|注意 |
| ----- |
| - 用于此语句的动态采样 (level=2) |
您从查询中得到一个非常不同的解释计划:
EXPLAIN PLAN FOR
select t.tab_key,
t.x,
t.y,
t.val,
s.val val2,
sqrt(power(t.x - s.x, 2) + power(t.y - s.y, 2)) d
from table1 t
join table1 s
on ( s.val is not null
and s.tab_key != t.tab_key
and power(t.x - s.x, 2) + power(t.y - s.y, 2) <= power(290, 2)
);
SELECT PLAN_TABLE_OUTPUT FROM TABLE(DBMS_XPLAN.DISPLAY());
给予:
|计划表输出 |
| :------------------------------------------------ -------------------------------------------- |
|计划哈希值:806357607 |
| |
| -------------------------------------------------- -------------------------------------------- |
| |身份证 |操作 |姓名 |行 |字节 |成本 (%CPU)|时间 | |
| -------------------------------------------------- -------------------------------------------- |
| | 0 |选择声明 | | 1 | 104 | 4 (0)| 00:00:01 | |
| | 1 |嵌套循环 | | 1 | 104 | 4 (0)| 00:00:01 | |
| | 2 |索引全扫描 |表 1__TK_V_X_Y_IDX | 5 | 260 | 1 (0)| 00:00:01 | |
| |* 3 |索引快速全扫描|表 1__TK_V_X_Y_IDX | 1 | 52 | 1 (0)| 00:00:01 | |
| -------------------------------------------------- -------------------------------------------- |
| |
|谓词信息(由操作 id 标识):|
| -------------------------------------------------- - |
| |
| 3 - 过滤器(“S”。“VAL”不为空且“S”。“TAB_KEY”“T”。“TAB_KEY” AND |
| POWER("T"."X"-"S"."X",2)+POWER("T"."Y"-"S"."Y",2)
db小提琴here