我正在Oracle DB上运行此查询:
SELECT COUNT(1) FROM db.table WHERE columnA = 'VALUE' AND ROWNUM < 2
columnA上没有索引,该表有数千行(可能是数百万行)。应该返回大约20个值,因此不会返回大量的值。但是,因为它会触发全表扫描,所以需要很长时间。我怎样才能让它变得更快?
注意:我不是DBA,所以我对数据库的访问权限有限,无法实现重组,添加索引或删除旧数据。
答案 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.