【问题标题】:Oracle Optimize QueryOracle 优化查询
【发布时间】:2020-06-26 17:54:55
【问题描述】:

我正在使用 oracle pl/sql,并且我有一个带有此查询的存储过程,它有点令人费解,但它完成了工作,问题是它需要大约 35 分钟,而 sql 开发人员 Autotrace表示即使表有索引,也会进行全面扫描。

那么有什么办法可以改进这个查询吗?

select tipotrx, sum(saldo) as saldo, 
count(*) as totaltrx from (
 select  max(ids) as IDTRX, max(monto) as monto, min(saldo) as saldo, max(aq_data) as aq_data, thekey, tipotrx
 from (
       select t.SID as ids, (TO_NUMBER(SUBSTR(P.P1, 18, 12))) as monto,
       ((TO_NUMBER(SUBSTR(P.P1, 18, 12)) * (TO_NUMBER(SUBSTR(t.acquirer_data, 13,2)) - 
       TO_NUMBER(SUBSTR(P.P4, 3,2))))) as saldo,
       (TO_CHAR(t.trx_date, 'YYMMDD') || t.auth_code || t.trx_amount || (SELECT 
       functions.decrypt(t.card_number) FROM DUAL)) as thekey,
       t.acquirer_data AS aq_data,
       TO_NUMBER(SUBSTR(t.acquirer_data, 12, 1)) as tipotrx
       from TBL_TRX t INNER JOIN TBL_POS P ON (t.SID = P.transaction) 
       WHERE (TO_NUMBER(SUBSTR(t.acquirer_data, 13,2)) >= TO_NUMBER(SUBSTR(P.P4, 3,2))) 
       AND trunc(t.INC_DATE)  between (TO_DATE('20/06/2020', 'DD/MM/YYYY') - 35) AND TO_DATE('20/06/2020', 'DD/MM/YYYY')
  ) t
  group by thekey,  tipotrx order by max(ids) desc) j 
group by tipotrx;

谢谢。

【问题讨论】:

  • 提供样本数据、期望的结果以及您想要完成的任务的说明。
  • 您正在处理一个多月的数据。我认为这是针对每晚/批处理,而不是针对交互式用户。当前执行时间是多少?您的目标执行时间是多少?
  • order by max(ids) desc 在查询中无效。你应该删除它。
  • SELECT functions.decrypt(t.card_number) FROM DUAL 可以只替换为 functions.decrypt(t.card_number)
  • @TheImpaler 很遗憾它是为用户服务的,是的,它正在搜索过去 35 天,客户告诉我他们每天处理大约 90.000 条记录,所以在那个月他们获得了超过 300 万条记录,我将按 max(ids) 删除订单

标签: sql oracle


【解决方案1】:

大多数情况下,索引必须与 WHERE 子句中的内容完全匹配才能使用。当您的 WHERE 子句显示时,不能使用 acquirer_data 列上的索引

 TO_NUMBER(SUBSTR(t.acquirer_data, 13,2))

当您的 WHERE 子句显示时,不能使用 INC_DATE 上的索引

 trunc(t.INC_DATE)

您操作 WHERE 子句中的每一列,仅此一项就可能阻止使用任何正常索引。

但是,如果您创建function-based 索引,则可以创建一些与 WHERE 子句中的内容匹配的新索引。这样至少数据库有可能使用索引而不是进行全表扫描。

--example function based index.
 CREATE INDEX TRUNC_INC_DATE ON TBL_TRX (trunc(t.INC_DATE));

当然,新索引会占用更多空间并增加它们自己的开销。继续使用该自动跟踪,看看是否值得。

此外,更新表统计信息也可能不会受到影响。

【讨论】:

  • 我会尝试使用 trunc(INC_DATE) 的索引,嗯,问题是 acquirer_data 有很多必要的信息,所以它不是可选的子字符串。
  • 可以向列添加多少基于函数的索引没有限制。如果您仍然需要在 acquirer_data 上为其他使用完整值的查询建立正常索引,那很好。您仍然可以在“TO_NUMBER(SUBSTR(t.acquirer_data, 13,2))”上添加基于函数的索引并保留所有现有索引。
  • 我刚刚想到了其他事情,您需要截断 INC_DATE 吗?
【解决方案2】:

改变这个:

trunc(t.INC_DATE) between (TO_DATE('20/06/2020', 'DD/MM/YYYY') - 35)
                       AND TO_DATE('20/06/2020', 'DD/MM/YYYY')

到这里:

t.INC_DATE between (TO_DATE('20/06/2020', 'DD/MM/YYYY') - 35)
                AND TO_DATE('21/06/2020', 'DD/MM/YYYY') - INTERVAL '1' SECOND

您可以将谓词修改为可搜索的(能够使用索引),而不是构建基于函数的索引。不要使用TRUNC 从列中减去,而是在上限文字上添加一天减去一秒。

代码比较混乱,但应该能够利用索引。但是,35 天的数据量可能很大;日期索引可能不是很有用,您可能需要查看其他谓词。

【讨论】:

    猜你喜欢
    • 2015-02-26
    • 2011-01-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多