使用TO CHAR函数优化查询

时间:2016-06-23 14:07:25

标签: sql oracle reporting-services oracle11g ssrs-2008

我有一个相当大的SELECT查询,但它通常只运行大约1.5 / 2分钟,但是在添加另一个时,我不得不在左外连接上使用to_char函数来解决“无效数字”错误

现在,我的查询需要10分钟以上,并且已经在SSRS中超时了。是否有更好的替代to_char?我在这个条款中使用它:

left outer join ifsapp.customer_order_line col on col.order_no = fa.order_ref_1 and col.line_no = fa.order_ref_2 and col.rel_no = fa.order_ref_3 and to_char(col.line_item_no) = fa.order_ref_4

line_item_no字段是“数字”类型,order_ref_4字段是“varchar2(20)”类型。

我可以使用演员或转换来提高效率吗?

3 个答案:

答案 0 :(得分:3)

尝试使用字符串格式的表添加索引:

CREATE INDEX char_ind
 ON ifsapp.customer_order_line (TO_CHAR(line_item_no));

答案 1 :(得分:2)

我建议您在开始报告之前修复字段order_ref_4。如果您创建索引(如果您有授权),则应该在(order_no,line_no,col.rel_no,to_char(col.line_item_no))上执行此操作。请参阅解释计划以找到确切的问题。 regexp_like + to_number也不会更快,特别是当fa表很大时,to_number将无法在fa表上使用索引。

最好拥有一致的数据。标记为错误或修复order_ref_4中的错误号码。你可以找到像这样的错误

select distinct fa.order_ref_4 from fa
where  TRANSLATE(fa.order_ref_4,'0123456789',' ')  is not null

如果只有一个案例不是样本的数字' *'使用这个

and (fa.order_ref_4 <> '*' and col.line_item_no = fa.order_ref_4) 

否则试试这个

and (TRANSLATE(fa.order_ref_4,'0123456789',' ')  is null and col.line_item_no = fa.order_ref_4) 

第二个将再次无法在fa上使用索引。

答案 2 :(得分:1)

使用to_char()导致所有line_item_no值 - 或至少所有与其他过滤器相匹配的行(取决于优化程序选择的计划)在之前转换为字符串可以将它们与order_ref_4进行比较。除了为了进行转换而添加少量开销之外,更严重的是它将阻止使用该列上的任何索引。执行时间的差异表明正在发生的事情 - 您可以查看旧查询和新查询的执行计划,以查看其他可能已更改的内容。

您可以检查order_ref_4值是否可以转换为比较右侧的数字,这样就可以使用line_item_no上的任何索引:

   and col.line_item_no =
     case when regexp_like(fa.order_ref_4, '^\d+$')
       then to_number(fa.order_ref_4) end

如果它有任何非数字字符,那么它将尝试匹配null - 当然,它不会与=匹配,因为空值无法与相等进行比较。这也只适用于正整数(因为减号或十进制字符不匹配\d),但我认为订单项编号为整数。

如果regexp_like()太慢,如果你有很多数据可能就是这样,那么你可以使用translate() - 与Mottor的答案相同的想法,但仍然保护to_number()

   and col.line_item_no =
     case when translate(fa.order_ref_4, '0123456789', ' ') is null
       then to_number(fa.order_ref_4) end

在通用文本字段中存储不同类型的数据会引发这些问题。您应该将数据存储在正确类型的列中 - 数字作为数字,日期作为日期等等。