Oracle:加速计数(*)?

时间:2009-11-25 00:24:27

标签: oracle

我有一个应用程序与cake / php放在一起。它的 非常好,但他们的数据寻呼机做到了这一点:

SELECT COUNT(*) AS COUNT
FROM foo f
LEFT JOIN bar b 
ON (f.asset_group_id = b.asset_group_id)
WHERE 1                    = 1

有可能加快这个速度吗?

更新:表格定义(删除了额外的列):

create table bar (
      last_modified_by varchar2(16), 
      asset_group_id number(10,0) not null enable, 
      folder varchar2(512) not null enable, 
      name varchar2(512) not null enable, 
      kind varchar2(16),
      -- exta fields deleted
       constraint bar_pk primary key (folder, name) enable
 );

create index bar_last_modified_date on bar (last_modified_date desc) ;
create index bar_asset_group_id on bar (asset_group_id desc) ;
create index bar_folder on bar (folder) ;
create index bar_kind on bar (kind) ;
create unique index bar_pk on bar (folder, name) ;

create table foo (
      created_date date not null enable, 
      asset_group_id number(10,0) not null enable, 
      keyword varchar2(4000) not null enable, 
      -- exta fields deleted
      constraint foo_pk primary key (asset_group_id, keyword) enable
)  enable row movement ;

create index foo_created on foo (created_date desc) ;
create unique index foo_pk on foo (asset_group_id, keyword) ;

10 个答案:

答案 0 :(得分:3)

如果两个asset_group_id列都没有索引,那么可以构建一些索引。

答案 1 :(得分:2)

物化视图可能会有所帮助。然后,这可能会减慢插入基础表的速度,如果有大量插入,这可能是一个问题。

答案 2 :(得分:2)

您可以使用嵌套在另一个快速刷新物化视图上的快速刷新物化视图。

(我插入样本数据)

create table bar (
      last_modified_by varchar2(16), 
      asset_group_id number(10,0) not null enable, 
      folder varchar2(512) not null enable, 
      name varchar2(512) not null enable, 
      -- exta fields deleted
       constraint bar_pk primary key (folder, name) enable
 );

create index bar_asset_group_id on bar (asset_group_id desc) ;
create index bar_folder on bar (folder) ;
create index bar_kind on bar (kind) ;

insert into bar values ('deew',1,'A','B');
insert into bar values ('deew',1,'A','C');
insert into bar values ('deew',1,'B','C');
insert into bar values ('deew',2,'E','C');

commit;

create table foo (
      created_date date not null enable, 
      asset_group_id number(10,0) not null enable, 
      keyword varchar2(4000) not null enable, 
      -- exta fields deleted
      constraint foo_pk primary key (asset_group_id, keyword) enable
)  enable row movement ;


insert into foo values (sysdate,1,'dd');
insert into foo values (sysdate,2,'dd');
insert into foo values (sysdate,3,'dd');
insert into foo values (sysdate,1,'ddE');

commit;

create index foo_created on foo (created_date desc) ;

create materialized view log on bar with rowid including new values;
create materialized view log on foo with rowid including new values;

create materialized view foobar_count_helper 
refresh fast on commit
as
select f.rowid rowid_f
,      b.rowid rowid_b
from   foo f
,      bar b
where  f.asset_group_id = b.asset_group_id (+)
/

create materialized view log on foobar_count_helper with rowid including new values; 

create materialized view foobar_count
refresh fast on commit
as
select count(*) count
from   foobar_count_helper
/

测试结果:

SQL> 
SQL> 
SQL> select * from foobar_count;

     COUNT
----------
         8

SQL> 
SQL> SELECT COUNT(*) AS COUNT
  2  FROM foo f
  3  LEFT JOIN bar b
  4  ON (f.asset_group_id = b.asset_group_id)
  5  where 1=1
  6  /

     COUNT
----------
         8

答案 3 :(得分:1)

没有任何方法可以修改SQL以使其更快 - 它已经是一个相当基本的查询。您可能能够修改表本身的各个方面(索引等),但SQL本身就是您可以获得所需信息的最有效表示。

答案 4 :(得分:1)

确保将f.asset_group_idb.asset_group_id编入索引。

我相信内部计数(*)和计数(1)在Oracle中执行相同的提取(无)。

问候
ķ

ps,如果您已获得企业版,则可以在f.asset_group_id上创建位图连接索引,b.asset_group_id以获得一些真正的查找速度: - )

答案 5 :(得分:1)

您确实拥有涉及资产组ID的索引,但其中一个是降序,另一个也是关键字列。让我们询问Oracle查询规划器是否在您的查询中使用这些:

EXPLAIN SELECT COUNT(*) ...  

如果您可以发布这些结果,那将为我们提供大量信息。

如果不使用当前索引,我希望这些索引能够正常工作:

create index bar_asset_group_id on bar (asset_group_id);
create index foo_asset_group_id on foo (asset_group_id);

为了清晰起见,将当前bar_asset_group_id重命名为bar_asset_group_id_desc

并删除WHERE 1 = 1:它(几乎完全)无害,但非常不必要。

答案 6 :(得分:0)

取决于数据,foo.asset_group_idbar.asset_group_id之间的相关性。您需要检查计划以查看哪个表正在驱动查询,它正在使用哪种连接方法。例如,如果其中一个表比另一个表小一个数量级,则可能更喜欢散列连接而不是嵌套循环+索引查找。另一个选项(特别是如果两个表都非常大)是排序合并,在asset_group_id列的两个列上都有合适的索引。

答案 7 :(得分:0)

如果对foobar编制索引并且两个表都有最新的统计信息,那么count(*)通常会以最有效的方式返回行数。

也许它只是一个大表,在这种情况下,在遍历表内容之前获取完整的最新行数只会是昂贵的。

有几种解决方法:

  1. 不要担心有多少页的结果 - “第1页的3439”并不比“第1页的批次”更有用。

  2. 预先计算结果并根据需要定期更新。例如,如果行数是24小时就可以了吗?

答案 8 :(得分:0)

在提供任何有用的答案之前,确实需要有关表格设计的更多信息。该查询包括一个外部联接,如果asset_group_idbar的主键,则连接甚至不是必需的....但没有表定义就无法知道。

答案 9 :(得分:-5)

这种加速的方法,尝试用Count(ColumnNo1,ColumnNo2,...)替换Count(*),其中使用的星号可能是那里的减速因为每次数据库必须解决的问题是什么asterisk意味着...通过在sql中包含特定的列名,您可以有效地减轻数据库在必须计算出该表中使用的列的位置。

希望这有帮助, 最好的祝福, 汤姆。