如何优化Oracle SQL查询?

时间:2018-05-25 05:12:26

标签: sql oracle performance oracle10g

我使用了这个查询

SELECT grirno, grirdate 
FROM   grirmain 
WHERE  grirno NOT IN (SELECT grir 
                      FROM   billcrown 
                      WHERE  grir IS NOT NULL) 

但需要578毫秒。请优化此查询

4 个答案:

答案 0 :(得分:0)

大多数情况下,使用NOT IN会降低查询性能。

对于您的情况,我建议您使用两套MINUS作为:

SELECT grirno, grirdate
  FROM grirmain
 MINUS  
SELECT grirno, grirdate
  FROM grirmain 
 WHERE grirno IN (SELECT grir 
                    FROM billcrown 
                   WHERE grir IS NOT NULL);

通过这种方式,查询可能会使列grirno上的索引受益(如果它是主键列,它自然会有索引),而在NOT IN的情况下,索引不能使用。< / p>

答案 1 :(得分:0)

我会将查询编写为foreach并添加索引:

not exists

您想要的索引位于SELECT m.grirno, m.grirdate FROM grirmain m WHERE NOT EXISTS (SELECT 1 FROM billcrown bc WHERE bc.grir = m.grirno ) ;

答案 2 :(得分:0)

提供更多信息会很有帮助,因为根据没有表和索引定义以及数据量的单个查询,很难说半秒是否是最佳的。

通常,除非子查询可能返回空值(即,如果billcrown.grir可以为空并且您没有指定where grir is not null)或者您有一些非标准设置,则{{1} }和[NOT] EXISTS版本是相同的,并且将具有相同的执行计划,并将其中一个重写为另一个是浪费时间。

测试设置(Oracle 12.2,但这一切都没有改变):

[NOT] IN

create table grirmain ( grirno integer generated always as identity constraint grimain_pk primary key , grirdate date default on null sysdate ); create table billcrown ( grir constraint billcrown_grimain_fk references grirmain , dummy varchar2(50) ); insert into grirmain (grirdate) select sysdate - dbms_random.value(0,10000) from dual connect by rownum <= 1e6; insert into billcrown (grir, dummy) select grirno, dbms_random.string('A',50) from grirmain where mod(grirno,10) = 1 union all select null, dbms_random.string('A',50) from grirmain where rownum <= 1000; commit; begin dbms_stats.gather_table_stats(user,'grirmain'); dbms_stats.gather_table_stats(user,'billcrown'); end; / 版本的执行计划(运行几次以消除缓存问题 - 在大约7秒内完成):

not in

SQL> set autotrace trace exp stat SQL> r 1 select grirno, grirdate 2 from grirmain 3 where grirno not in 4 ( select grir 5 from billcrown 6* where grir is not null ) 900000 rows selected. Execution Plan ---------------------------------------------------------- Plan hash value: 56519876 ------------------------------------------------------------------------------------------ | Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time | ------------------------------------------------------------------------------------------ | 0 | SELECT STATEMENT | | 901K| 15M| | 2194 (1)| 00:00:01 | |* 1 | HASH JOIN RIGHT ANTI| | 901K| 15M| 1664K| 2194 (1)| 00:00:01 | |* 2 | TABLE ACCESS FULL | BILLCROWN | 100K| 488K| | 239 (1)| 00:00:01 | | 3 | TABLE ACCESS FULL | GRIRMAIN | 1000K| 12M| | 687 (1)| 00:00:01 | ------------------------------------------------------------------------------------------ Predicate Information (identified by operation id): --------------------------------------------------- 1 - access("GRIRNO"="GRIR") 2 - filter("GRIR" IS NOT NULL) Statistics ---------------------------------------------------------- 0 recursive calls 0 db block gets 63225 consistent gets 0 physical reads 0 redo size 24221330 bytes sent via SQL*Net to client 660596 bytes received via SQL*Net from client 60001 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 900000 rows processed 版本的执行计划:

NOT EXISTS

SQL> select grirno, grirdate 2 from grirmain 3 where not exists 4 ( select grir 5 from billcrown 6 where grir is not null 7 and grir = grirno ); 900000 rows selected. Execution Plan ---------------------------------------------------------- Plan hash value: 56519876 ------------------------------------------------------------------------------------------ | Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time | ------------------------------------------------------------------------------------------ | 0 | SELECT STATEMENT | | 901K| 15M| | 2194 (1)| 00:00:01 | |* 1 | HASH JOIN RIGHT ANTI| | 901K| 15M| 1664K| 2194 (1)| 00:00:01 | |* 2 | TABLE ACCESS FULL | BILLCROWN | 100K| 488K| | 239 (1)| 00:00:01 | | 3 | TABLE ACCESS FULL | GRIRMAIN | 1000K| 12M| | 687 (1)| 00:00:01 | ------------------------------------------------------------------------------------------ Predicate Information (identified by operation id): --------------------------------------------------- 1 - access("GRIR"="GRIRNO") 2 - filter("GRIR" IS NOT NULL) Statistics ---------------------------------------------------------- 1 recursive calls 0 db block gets 63225 consistent gets 0 physical reads 0 redo size 24221330 bytes sent via SQL*Net to client 660596 bytes received via SQL*Net from client 60001 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 900000 rows processed 添加索引允许索引快速全扫描而不是表扫描(这样做的好处将取决于表中有多少块 - 在我的示例中,它只有两个小列所以好处很小):

bill crown.grir

答案 3 :(得分:-2)

虽然这取决于您的数据大小和索引。您可以根据需要在where子句上创建索引作为缩略图规则 尝试使用以下选项

run_dir=/var/run/myscript # change the name as appropriate    
check_step() {
  step=$1
  step_file=$run_dir/$step.step.done
  if [ ! -f "$step_file" ]; then
    return 0
  else
    echo "Step $step skipped"
    return 1
  fi
}

step_done()  {
  touch "$run_dir/$1.step.done" && echo finished step $1
}

mkdir -p "$run_dir"
check_step upgrade  && freebsd-update upgrade -r 11.1-RELEASE && step_done upgrade
check_step install1 && freebsd-update install && step_done install1
shutdown -r now
check_step install2 && freebsd-update install && step_done install2