【发布时间】:2014-04-11 04:49:38
【问题描述】:
我的任务是优化 Oracle SQL 中的查询,其中使用与其中一列中 varchar 数据的已解析片段有关的条件将表与自身连接起来。据我了解,Oracle 不会使用索引,因为 ON 子句中的列名仅作为函数的参数出现。查询几乎需要永远完成。使用已处理的 REF 数据创建一个表(见下文)可以解决问题,但由于其他原因,这是不可能的。
我已经准备了一个简化版本的问题来说明(我很确定这是线索,所以我提取了一个更复杂的查询的相关部分)。 “交易”表包含以下列:
- TRAN -- 一个 10 位数字,是交易代码,
- STORE -- 进行交易的商店代码,
- DATE -- 交易日期,
-
REF -- 不同交易的参考代码(在退货等情况下)。此代码的格式为:[商店代码] * [交易年份的最后两位数] * [TRAN 的最后 7 位不带左侧零的数字],因此它看起来像这样:'142*09*3234'。基本上,REF 指向表中的其他行,但在使用之前必须进行一些处理。
SELECT * FROM transactions t1 JOIN transactions t2 ON ( t2.store = substr(t1.REF, 1, instr(t1.REF, '*') - 1) AND to_char(t2.DATE, 'yy') = substr(t1.REF, instr(t1.REF, '*', 1, 1) + 1), instr(t1.REF, '*', 1, 2) - 1) AND to_number(substr(to_char(t2.TRAN), -7)) = to_number(substr(t1.REF, instr(t1.REF, '*', 1, 2) + 1)) )
我没有处理 SQL 优化的经验,所以如果有任何好的方向建议,我将不胜感激。
【问题讨论】:
-
也许这个 SO 问题会对您有所帮助,也请阅读 cmets:stackoverflow.com/questions/2486952/…,但瓶颈可能在这一行
...to_char(t2.DATE, 'yy')... -
这个加入太可怕了……
-
解释计划将帮助我们排除故障。例如,优化器可能大大低估了联接的基数,从而导致 NESTED LOOP 而不是 HASH JOIN。在这种情况下,
USE_HASH(t1 t2)提示或有关条件的扩展统计信息可能会有所帮助。但这只是一个没有执行计划的疯狂猜测。 -
我找到了一个出乎意料的解决方案。我不确定它为什么会起作用,但是使用与查询中嵌套的 substr 和 instr 函数完全相同的存储函数,将速度提高了大约十倍,这对我来说已经足够了。
-
@Tosz 您是否使用了单个函数而不是 3 个条件?对于一个函数或一个复杂的谓词,Oracle 无法做出准确的基数估计,通常只是做出一个疯狂的猜测(我认为 5% 是默认值)。单个函数 (.05) 可能导致比多个谓词 (.05 * .05 * .05) 更好的估计,从而产生更好的计划。
标签: sql oracle optimization query-optimization