【问题标题】:My Oracle query alters between very short and very long execution times. What can cause this?我的 Oracle 查询在非常短和非常长的执行时间之间变化。什么会导致这种情况?
【发布时间】:2012-04-15 22:46:48
【问题描述】:

[抱歉,如果我重复发布此信息 - 我以为我在上周五发布了一个问题,但我的帐户没有显示任何问题。]

主要问题:Linux 上的 Oracle 11g 在 4 秒和 1.000 秒之间交替完成和返回一个特定查询的数据。 Oracle 在两个不同的执行计划之间来回切换,其中一个执行计划非常缓慢。

我们已经确定了几个语义相同的查询更改,这使得 Oracle 不断选择快速执行计划。我们担心无缘无故的来回切换会导致错误或数据损坏。

任何关于此行为原因的想法将不胜感激。

以下是具体细节:

我们对一个模式的四个简单表进行了非常简单的 Oracle 查询。当我们运行这个查询时,我们会得到截然不同的执行时间——如果我们按顺序运行 20 次,其中三到四次执行需要 4 秒才能返回数据,其他执行需要超过 1.000 秒。

我们尝试记录执行计划,Oracle 在两个不同的执行计划之间进行更改 - 一个计划给出 4 秒响应,另一个给出 1.000+ 秒响应。

每个表大约有 30.000 行,响应大约有 5.000 行。当 Oracle 选择慢速执行计划时,获取每个结果行的时间会呈指数级增长 - 响应的前 1.000 行需要 2 秒,第 1.000-2.000 行需要 30 秒,第 2.000-3.000 行需要 90 秒,依此类推.

我们在使用的列上有索引,并且为了快速执行计划,它们按预期使用。慢速计划总是对其中一个索引进行“FAST FULL SCAN”(成本约为 2.000),而快速计划则对同一索引进行“RANGE SCAN”(成本约为 2) .计划完全不同——也许正因为如此。我们已经尝试 DROP:ing 这个索引并重新 CREATE:ing 它,但结果没有区别。

此外,查询在其中一个表的主键列上包含 NOT LIKE。如果我们将这些 NOT LIKE 表达式改为针对引用列,Oracle 总是选择快速执行计划。

我们不想锁定执行计划,因为预计查询会发生微妙的变化。此外,执行计划之间的这种来回变化让我们感到担忧——它闻到了错误或数据损坏的味道。

有没有人知道甲骨文为什么会这样?除了锁定执行计划之外,还有其他方法吗?

这是在快速和慢速执行计划之间切换的查询:

select g.ucid, a.ucid
from account a, groups g, group_members gm, group_groups_flat ggf
where a.ucid = gm.ucid_member
and gm.ucid_group = ggf.ucid_member
and ggf.ucid_group = g.ucid
and a.status = 'active'
and g.unix_gid is not null
and gm.valid_from <= sysdate
and gm.valid_to >= sysdate
and g.ucid not like '$_%' escape '$'
and g.ucid not like 's$_%' escape '$'

如果我对引用列而不是主键列执行 NOT LIKE,则查询总是很快:

select g.ucid, a.ucid
from account a, groups g, group_members gm, group_groups_flat ggf
where a.ucid = gm.ucid_member
and gm.ucid_group = ggf.ucid_member
and ggf.ucid_group = g.ucid
and a.status = 'active'
and g.unix_gid is not null
and gm.valid_from <= sysdate
and gm.valid_to >= sysdate
and ggf.ucid_group not like '$_%' escape '$'
and ggf.ucid_group not like 's$_%' escape '$'

如果我删除帐户表(“a.status = 'active'”)或组表(“g.unix_gid 不为空”)上的限制,查询总是很快,但当然会返回更多行。但是,它确实会在相当稳定的 10 秒内返回 30.000 行(相对于更受限制的查询的缓慢执行计划在 1.000 秒内返回 5.000 行)。

查询中涉及的架构的相关部分是:

CREATE TABLE "PDB"."GROUPS"
(
  "UCID"        VARCHAR2(256 BYTE),    
  "UNIX_GID"    NUMBER(*,0),
  [...]

  PRIMARY KEY ("UCID") USING INDEX PCTFREE 10 INITRANS 2 MAXTRANS 255 COMPUTE STATISTICS STORAGE(INITIAL 3145728 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT) TABLESPACE "PDB" ENABLE,

  CONSTRAINT "GN_FK" FOREIGN KEY ("UCID") REFERENCES "PDB"."NAMESPACE" ("UCID") ENABLE
)
CREATE TABLE "PDB"."ACCOUNT"
(
  "UCID"           VARCHAR2(256 BYTE),
  "STATUS"         VARCHAR2(10 BYTE) NOT NULL ENABLE,
  [...]

  PRIMARY KEY ("UCID") USING INDEX PCTFREE 10 INITRANS 2 MAXTRANS 255 COMPUTE STATISTICS STORAGE(INITIAL 2097152 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT) TABLESPACE "PDB" ENABLE,

  FOREIGN KEY ("STATUS") REFERENCES "PDB"."ACCOUNT_STATUS" ("STATUS") ENABLE,
  CONSTRAINT "AN_FK" FOREIGN KEY ("UCID") REFERENCES "PDB"."NAMESPACE" ("UCID") ENABLE,
)
CREATE TABLE "PDB"."GROUP_MEMBERS"
(
  "UCID_GROUP"  VARCHAR2(256 BYTE) NOT NULL ENABLE,
  "UCID_MEMBER" VARCHAR2(256 BYTE) NOT NULL ENABLE,
  "VALID_FROM" DATE NOT NULL ENABLE,
  "VALID_TO" DATE NOT NULL ENABLE,
  CONSTRAINT "GROUP_MEMBERS_GROUPS_FK1" FOREIGN KEY ("UCID_GROUP") REFERENCES "PDB"."GROUPS" ("UCID") ENABLE,
  CONSTRAINT "GROUP_MEMBERS_MEMBER_FK1" FOREIGN KEY ("UCID_MEMBER") REFERENCES "PDB"."ACCOUNT" ("UCID") ENABLE
)
CREATE INDEX "PDB"."IDX_GROUP_MEMBERS_FROM" ON "PDB"."GROUP_MEMBERS"("VALID_FROM")
CREATE INDEX "PDB"."IDX_GROUP_MEMBERS_TO" ON "PDB"."GROUP_MEMBERS"("VALID_TO")
CREATE TABLE "PDB"."GROUP_GROUPS_FLAT"
(
  "UCID_GROUP"  VARCHAR2(256 BYTE),
  "UCID_MEMBER" VARCHAR2(256 BYTE),
  CONSTRAINT "GROUP_GROUPS_FLAT_GROUPS_FK1" FOREIGN KEY ("UCID_GROUP") REFERENCES "PDB"."GROUPS" ("UCID") ENABLE,
  CONSTRAINT "GROUP_GROUPS_FLAT_GROUPS_FK2" FOREIGN KEY ("UCID_MEMBER") REFERENCES "PDB"."GROUPS" ("UCID") ENABLE
)
CREATE INDEX "PDB"."IDX_GROUP_GROUPS_FLAT_GROUP" ON "PDB"."GROUP_GROUPS_FLAT("UCID_GROUP")
CREATE INDEX "PDB"."IDX_GROUP_GROUPS_FLAT_MEMBER" ON "PDB"."GROUP_GROUPS_FLAT("UCID_MEMBER")

【问题讨论】:

  • 你之前确实问过这个问题,但在Database Administrators - 你的问题是here。您的帐户似乎没有关联。对于这类问题,这可能是更合适的论坛。

标签: performance oracle


【解决方案1】:

如果您使用的是 11g,则可以使用计划管理来阻止 Oracle 切换计划。

http://www.oracle-base.com/articles/11g/sql-plan-management-11gr1.php

【讨论】:

    【解决方案2】:

    您提供的信息有些不一致。在这个问题中,您说一个计划使用FAST FULL SCAN,而另一个计划在同一索引上使用RANGE SCAN;但是在 dbas 站点上的问题版本中,您显示了实际的执行计划,并且都使用 FAST FULL SCAN 作为唯一基于索引的操作。两个计划之间的真正区别似乎在于连接顺序,其中由于第一个要连接的表之间缺乏连接条件,第二个顺序需要进行一些更大的内存操作。

    无论如何,对于如何进一步调查,我有一些建议。一个想法是激活tracing event 10053,它会记录所有优化器活动,并查看是否可以比较获得两个不同计划的运行结果。输出不是很漂亮,可能难以理解,但它可能会让您对正在发生的事情有所了解。

    我的另一个想法是,您在查询中使用的唯一非文字值是SYSDATE,所以我想知道时间的变化是否会导致优化器的算法发生变化,从而产生不同的计划。我不确定优化器如何处理 SYSDATE。您可以尝试使用绑定变量替换对 SYSDATE 的调用,并在执行查询之前在其他代码中设置日期值。

    【讨论】:

    • 对不一致之处表示歉意。我已经为这个问题困扰了五天——RANGE SCAN 实际上是在同一个 Oracle 实例中以相同模式(但数据较少)生成的计划。关于 SYSDATE 的想法非常有趣。我尝试用 TO_DATE() 文字替换 SYSDATE,但不幸的是它并没有影响结果。仍然在高效和可怕之间来回转换。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-28
    相关资源
    最近更新 更多