【问题标题】:How can I make this query faster?我怎样才能使这个查询更快?
【发布时间】:2012-01-11 01:14:33
【问题描述】:

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

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

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

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

【问题讨论】:

  • 我们是否应该假设您不能在columnA 上创建索引以提高查询效率?而且,据我所知,您只想优化后一个查询,而不是前一个查询,对吗?

标签: sql oracle optimization


【解决方案1】:

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

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;

不到 0.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。

【讨论】:

  • 所以没有办法加快速度?除了索引?
  • @Malfist - 不。除非ColumnA 上有索引,否则数据库服务器将别无选择,只能扫描表并在找到一行后停止。如果您在 ColumnA 上构建非聚集索引,数据库将快速查找该行,然后为您提供 1 或空结果。
  • 您认为还有什么其他技术比专为它设计的技术更合适?如果需要,可以构建一个提交时物化视图,但这是一种更大的方法,并且需要更广泛的数据库更改。
  • 我知道索引是为此而设计的,但让 DBA 添加索引通常意味着我必须等待至少四个月才能批准和实施更改。
  • 告诉他们浪费了多少时间。该语句的运行频率如何?如果它每天运行 1000 次,时间差为 0.01 秒与 10 秒,问他们为什么愿意每天浪费 1,000,000 秒的用户时间和 I/O 带宽。
猜你喜欢
  • 2021-08-01
  • 2021-07-31
  • 2013-08-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-12-20
  • 1970-01-01
相关资源
最近更新 更多