如何更快地进行此查询?

时间:2012-01-10 16:10:02

标签: sql oracle optimization

我正在Oracle DB上运行此查询:

SELECT COUNT(1) FROM db.table WHERE columnA = 'VALUE' AND ROWNUM < 2

columnA上没有索引,该表有数千行(可能是数百万行)。应该返回大约20个值,因此不会返回大量的值。但是,因为它会触发全表扫描,所以需要很长时间。我怎样才能让它变得更快?

注意:我不是DBA,所以我对数据库的访问权限有限,无法实现重组,添加索引或删除旧数据。

1 个答案:

答案 0 :(得分:4)

如果您正在寻找存在的行,而不是它出现的次数,那么这将更合适:

SELECT 1 
  FROM DB.TABLE
 WHERE ColumnA = 'VALUE'
   AND ROWNUM = 1

一旦找到一行,这将尽快停止查询;但是,如果你需要它更快,那就是索引的用途。

测试用例:

create table q8806566
( id        number not null,
  column_a  number not null,
  padding   char(256),  -- so all the rows aren't really short
  constraint pk_q8806566 primary key (id) 
    using index tablespace users
)
tablespace users;

insert into q8806566 -- 4 million rows
  (id, column_a, padding)
with generator as
(select --+ materialize
        rownum as rn from dba_objects 
  where rownum <= 2000)
select rownum as id, mod(rownum, 20) as column_a, 
       v1.rn as padding
  from generator v1
       cross join generator v2;

commit;

exec dbms_stats.gather_table_stats (ownname => user, tabname => 'q8806566');

column_A的数据分布均匀,可以在前几个块中找到所有值,因此该查询运行良好:

SELECT 1    
  FROM q8806566
 WHERE Column_A = 1 
   AND ROWNUM = 1;

Sub .1秒执行时间和低I / O - 大约4个I / O.但是,当寻找一个不存在的值时,情况会发生变化:

SELECT 1    
  FROM q8806566
 WHERE Column_A = 20
   AND ROWNUM = 1;

执行时间为20-40秒,超过100,000个I / O.

但是,如果我们添加索引:

create index q8806566_idx01 on q8806566 (column_a) tablespace users;
exec dbms_stats.gather_index_stats (ownname => user, indname => 'q8806566_idx01');

我们从两个查询中得到低于0.1秒的响应时间和单位数I / O.