使用 TO CHAR 函数优化查询

Optimize query with TO CHAR function

我有一个相当大的 SELECT 查询,但它 运行 通常只有大约 1.5/2 分钟,但在添加另一块后,我不得不使用 to_char左外连接上的函数以解决 "invalid number" 错误。

现在,我的查询需要 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 字段是 "number" 类型,order_ref_4 字段是 "varchar2(20)" 类型。

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

尝试在 table 添加一个字符串格式的索引:

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

使用 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 - 当然不会与 = 匹配,因为 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

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

我建议您在开始报告之前修复字段 order_ref_4。如果您创建索引(如果您有资助),您应该在 (order_no,line_no,col.rel_no,to_char(col.line_item_no) 上进行。请参阅解释计划以找到确切的问题。 regexp_like + to_number 也不会更快,尤其是当 fa table 很大并且 to_number 将无法在 fa table 上使用索引时。

最好有一致的数据。标记为错误或修复 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 上的索引。