[道歉,如果我加倍发布 - 我以为我上周五发布了一个问题,但我的帐户没有显示任何问题。]
主要问题: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秒,依此类推
我们在使用的列上有索引,对于快速执行计划,它们按预期使用。慢速计划总是对其中一个索引进行“快速全扫描”(成本约为2000)而不是快速计划,它执行相同指数的“范围扫描”(成本约为2) 。计划完全不同 - 可能是因为这个原因。我们尝试过DROP:使用这个索引并重新创建它,但结果没有区别。
此外,该查询在其中一个表的主键列中包含NOT LIKE。如果我们将这些NOT LIKE表达式移到反对引用列,Oracle总是选择快速执行计划。
我们不想锁定执行计划,因为预期查询会巧妙地改变。此外,这在执行计划之间来回改变使我们感到担心 - 它有臭味或数据损坏。
有没有人有任何想法为什么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'”)或groups表(“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")
答案 0 :(得分:0)
您提供的信息存在一些不一致之处。在这个问题中,您说一个计划使用FAST FULL SCAN
而另一个计划在同一个索引上使用RANGE SCAN
;但是在dbas站点上的问题版本中,您显示了实际的执行计划,并且都使用FAST FULL SCAN
作为唯一的基于索引的操作。两个计划之间的真正区别似乎是连接顺序,其中第二个顺序需要一些较大的内存操作,因为要连接的第一个表之间缺少连接条件。
无论如何,我有一些关于如何进一步调查的建议。一个想法是激活tracing event 10053,它记录所有优化器活动,并查看是否可以比较获得两个不同计划的运行结果。输出不是很漂亮,很难理解,但它可能会让你知道发生了什么。
我的另一个想法是,你在查询中使用的唯一非文字值是SYSDATE
,所以我想知道时间的变化是否会导致优化器的算术发生变化,产生不同的计划。我不确定优化器如何处理SYSDATE。您可以尝试使用绑定变量替换对SYSDATE的调用,并在执行查询之前在其他代码中设置日期值。
答案 1 :(得分:0)
如果您使用11g,则可以使用计划管理来阻止Oracle切换计划。
http://www.oracle-base.com/articles/11g/sql-plan-management-11gr1.php