Oracle sql 查询(几乎)永远运行

Posted

技术标签:

【中文标题】Oracle sql 查询(几乎)永远运行【英文标题】:Oracle sql query running for (almost) forever 【发布时间】:2010-08-19 18:41:10 【问题描述】:

我的一个应用程序正在尝试执行 count(*) 查询,该查询在大约 30 分钟后返回。奇怪的是查询很简单,涉及的表很大,但并不庞大(10000条和50000条记录)。

需要 30 分钟的查询是:

select count(*) 
from RECORD r inner join GROUP g 
  on g.GROUP_ID = r.GROUP_ID 
where g.BATCH_ID = 1 and g.ENABLED = 'Y'

数据库架构本质上是:

create table BATCH (
    BATCH_ID int not null,
    [other columns]...,
    CONSTRAINT PK_BATCH PRIMARY KEY (BATCH_ID)
);

create table GROUP (
    GROUP_ID int not null,
    BATCH_ID int,
    ENABLED char(1) not null,
    [other columns]...,
    CONSTRAINT PK_GROUP PRIMARY KEY (GROUP_ID),
    CONSTRAINT FK_GROUP_BATCH_ID FOREIGN KEY (BATCH_ID)
        REFERENCES BATCH (BATCH_ID),
    CONSTRAINT CHK_GROUP_ENABLED CHECK(ENABLED in ('Y', 'N'))
);

create table RECORD (
    GROUP_ID int not null, 
    RECORD_NUMBER int not null,
    [other columns]...,
    CONSTRAINT PK_RECORD PRIMARY KEY (GROUP_ID, RECORD_NUMBER),
    CONSTRAINT FK_RECORD_GROUP_ID FOREIGN KEY (GROUP_ID)
        REFERENCES GROUP (GROUP_ID)
);

create index IDX_GROUP_BATCH_ID on GROUP(BATCH_ID);

我检查了数据库中是否有任何块,没有。我还运行了以下查询,除了最后两个之外的所有查询都立即返回:

select count(*) from RECORD -- 55,501

select count(*) from GROUP -- 11,693

select count(*) 
from RECORD r inner join GROUP g 
  on g.GROUP_ID = r.GROUP_ID
-- 55,501

select count(*) 
from GROUP g 
where g.BATCH_ID = 1 and g.ENABLED = 'Y' 
-- 3,112

select count(*) 
from RECORD r inner join GROUP g 
  on g.GROUP_ID = r.GROUP_ID 
where g.BATCH_ID = 1 
-- 27,742 - took around 5 minutes to run

select count(*) 
from RECORD r inner join GROUP g 
  on g.GROUP_ID = r.GROUP_ID 
where g.ENABLED = 'Y' 
-- 51,749 - took around 5 minutes to run

有人可以解释发生了什么吗?如何提高查询的性能?谢谢。

【问题讨论】:

【参考方案1】:

一位同事发现了这个问题。这是因为表统计信息没有更新,并且上次分析表是几个月前(当时表基本上是空的)。我运行了分析表 RECORD 计算统计信息,现在查询在不到一秒的时间内返回。

我必须与 DBA 谈谈为什么没有更新表统计信息。

【讨论】:

现在我很生气,我没想到这一点,这在我上线期间的工作环境中多次发生在我身上。 摇头。很高兴你们想通了。 我建议你随身携带一个大的线索蝙蝠。【参考方案2】:
SELECT COUNT(*)  
FROM   RECORD R
LEFT OUTER JOIN GROUP G ON G.GROUP_ID = R.GROUP_ID  
       AND G.BATCH_ID = 1
       AND G.ENABLED = 'Y'

试试看,然后告诉我结果如何。不是说这就是答案,但是由于我现在无法访问数据库,因此无法对其进行测试。希望它对你有用。

【讨论】:

超过 5 分钟。 尝试用 COUNT(*) 代替 COUNT(columnName) 看看是否有任何作用。怀疑它会,但值得短暂。【参考方案3】:

解释计划是一个很好的起点。

看这里:

Strange speed changes with sql query

了解如何使用解释计划语法(并查询以查看结果。)

如果这没有显示任何可疑之处,您可能需要查看痕迹。

【讨论】:

以上是关于Oracle sql 查询(几乎)永远运行的主要内容,如果未能解决你的问题,请参考以下文章

Oracle游标和游标变量的区别

Oracle SQL 查询在 JdbcTemplate 和 SimpleJdbcTemplate 中花费的时间太长

oracle 中sql执行超慢几乎查询不出来

Oracle:查找多个查询运行的总查询运行时间

Oracle SQL 查询运行缓慢

Java JDBC Oracle SQL 查询每隔几个月就会挂起一次