我有一个相当大的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)”类型。
我可以使用演员或转换来提高效率吗?
答案 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
在通用文本字段中存储不同类型的数据会引发这些问题。您应该将数据存储在正确类型的列中 - 数字作为数字,日期作为日期等等。