Oracle查询优化器在同一查询中有时会选择错误的计划

xxslljrj  于 2023-06-22  发布在  Oracle
关注(0)|答案(2)|浏览(134)

我让我的Jetty应用程序连接到Oracle数据库以持久化应用程序元数据。我有下面的应用程序触发的SQL查询:

select * from my_table
 where id = 'some_id' --> not unique, i can have repeated Ids
 and created > sysdate - 160/24 
 and started <= to_timestamp('07-06-2023 06:12:45', 'dd-mm-yyyy hh24:mi:ss') 
 and status in (3, 13, 14);

除起始列外,所有表列都已建立索引。
我观察到这个查询需要很长时间才能回复,大约5分钟。一般来说,它在几秒钟内就会被送达。在进一步深入研究之后,我们发现优化器在花费更长时间时选择了糟糕的计划。这一次是根据id列进行过滤。当它通过状态扫描时,它工作得很好。我尝试每7天对这个表进行一次分区,因为这个表的容量相当大(每天3000 - 4000万行)。它有帮助,但这个问题仍然没有永久消失。如何确保查询优化器始终使用良好的计划?

whitzsjs

whitzsjs1#

在不改变索引的情况下,您可以通过提示查询来获得稳定性。例如,如果status上的索引称为idx_status,则:

select /*+ INDEX(my_table idx_status) */ * from my_table
 where id = 'some_id' --> not unique, i can have repeated Ids
 and created > sysdate - 160/24 
 and started <= to_timestamp('07-06-2023 06:12:45', 'dd-mm-yyyy hh24:mi:ss') 
 and status in (3, 13, 14);

但是,如果您有大量的记录,这些记录的状态超过一周,那么您也会希望在索引级别将其清除。而且,如果id字段以任何显著的方式减少了结果,那么也应该被索引。如果是这种情况,那么您需要我们所说的连接或复合或多列索引。从左到右,从执行相等 predicate 的列开始,然后是执行IN的列,最后是执行范围/不等式的列。所以索引应该是:

CREATE OR REPLACE INDEX idx_composite ON my_table(id,status,created)

这可能会吸引优化器,以至于不需要任何提示就可以使用它。为了确保这一点,您应该删除ID上的现有索引,让这个新的复合索引代替它。这很可能会给你最好的表现。

jutyujz0

jutyujz02#

您可以使用SQL计划基线。像这样:

SET SERVEROUTPUT ON
DECLARE
  l_plans_loaded  PLS_INTEGER;
BEGIN
  l_plans_loaded := DBMS_SPM.load_plans_from_cursor_cache(
    sql_id => '&sql_id',
    plan_hash_value => '&plan_hash_value',
    sql_handle => '&handle');
  DBMS_OUTPUT.put_line('Plans Loaded: ' || l_plans_loaded);
END;
/

相关问题