如何使用大量and语句优化Oracle Query

时间:2019-08-19 11:44:40

标签: sql oracle query-optimization

我正在使用Select查询中的几个and语句从oracle表中选择数据。另外,我正在使用Like语句。问题是当我使用大表时,执行查询会花费太多时间。我该如何更改下面查询的某些部分。

SELECT t.co_filial as fil_code, t.emp_birth as emp_code, to_char(t.curr_day, 'YYYY-MM-DD') as operation_date, 
TRUNC(t.Sum_Pay/100) As summa
FROM operation_history t 
WHERE Substr(t.Co_Acc, 8) LIKE '12294%' And Substr(t.Co_Acc, -3) > 599 And Substr(t.Co_Acc, -3) != 683 And Substr(t.Co_Acc, -3) < 696
AND t.state_id = 41
And t.curr_day >= to_date('12.08.2019', 'DD.MM.YYYY')
And t.curr_day <  to_date('13.08.2019', 'DD.MM.YYYY')

3 个答案:

答案 0 :(得分:3)

一个明显的改进是:Substr的用于提取最后3个字符的字符串可以使用一次,而不是三次,并且可以在子查询中使用,如下所示。

SELECT fil_code,
  emp_code,
  operation_date,
  summa
From
  (SELECT t.co_filial as fil_code, 
     t.emp_birth as emp_code, 
     to_char(t.curr_day, 'YYYY-MM-DD') as operation_date, 
     TRUNC(t.Sum_Pay/100) As summa,
     Substr(t.Co_Acc, -3) AS SUBSTR_3 -- ADDED THIS
   FROM operation_history t 
  WHERE Substr(t.Co_Acc, 8, 5) = '12294' -- used direct equals operator 
  --And Substr(t.Co_Acc, -3) > 599 
  --And Substr(t.Co_Acc, -3) != 683 
  --And Substr(t.Co_Acc, -3) < 696
  AND t.state_id = 41
  And t.curr_day >= to_date('12.08.2019', 'DD.MM.YYYY')
  And t.curr_day <  to_date('13.08.2019', 'DD.MM.YYYY'))
-- added following where clause
WHERE SUBSTR_3 BETWEEN 600 AND 695
AND SUBSTR_3 != 683

我使用了between,其中包括上限值和下限值,因此要从相应的限制中加减1。

干杯!

答案 1 :(得分:0)

对于此查询(我已经进行了一些清理):

SELECT t.co_filial as fil_code, t.emp_birth as emp_code, to_char(t.curr_day, 'YYYY-MM-DD') as operation_date, 
        TRUNC(t.Sum_Pay/100) As summa
FROM operation_history t 
WHERE Substr(t.Co_Acc, 8) LIKE '45294%' And Substr(t.Co_Acc, -3) > 599 And
      Substr(t.Co_Acc, -3) <> 683 And
      Substr(t.Co_Acc, -3) < 696 AND 
      t.state_id = 41 And
      t.curr_day >= date '2019-08-12' and
      t.curr_day <  date '2019-08-13';

要使其运行更快,您想在WHERE子句上使用索引。那可能是唯一可以带来明显改善的东西。

我建议在operation_history(state_id, curr_date, Substr(t.Co_Acc, 8))上建立索引。

因为您只在结果中寻找一天,所以您还可以做另一件事:

SELECT t.co_filial as fil_code, t.emp_birth as emp_code, to_char(t.curr_day, 'YYYY-MM-DD') as operation_date, 
        TRUNC(t.Sum_Pay/100) As summa
FROM operation_history t 
WHERE Substr(t.Co_Acc, 8) LIKE '45294%' and
      Substr(t.Co_Acc, -3) > 599 and
      Substr(t.Co_Acc, -3) <> 683 and
      Substr(t.Co_Acc, -3) < 696 and 
      t.state_id = 41 and
      trunc(t.curr_day) = date '2019-08-12';

然后,所需的索引位于operation_history(state_id, trunc(curr_date), Substr(t.Co_Acc, 8))上。

答案 2 :(得分:0)

一些建议:

1)无需动态计算operation_date substr_3和summa字段,而是创建3个生成的(计算的)列,每个表达式一个。这些将在数据库中预先计算,您只需要选择计算列即可。快多了。列应该是持久性的(不是虚拟的)

https://oracle-base.com/articles/11g/virtual-columns-11gr1

2)检查是否可以对这些substr表达式进行相同操作

3)为您在2)中创建的计算列创建索引(如果有的话)

4)为stateid和curr_day创建索引

致谢