【问题标题】:Oracle sql query running for (almost) foreverOracle sql 查询(几乎)永远运行
【发布时间】: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

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

【问题讨论】:

    标签: sql oracle


    【解决方案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

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

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

    【讨论】:

      猜你喜欢
      • 2017-11-17
      • 1970-01-01
      • 1970-01-01
      • 2015-01-11
      • 1970-01-01
      • 2018-11-18
      • 2020-02-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多