Мой запрос Oracle изменяется между очень коротким и очень длинным временем выполнения.Что может вызвать это? - PullRequest
4 голосов
/ 02 апреля 2012

[Прошу прощения, если я дважды опубликую это - я думал, что отправил вопрос в прошлую пятницу, но мой аккаунт не показывает заданные вопросы.]

Основная проблема: Oracle 11g в Linux чередуется между завершением и возвратом данных для одного конкретного запроса за 4 секунды и 1000 секунд. Oracle переключается между двумя различными планами выполнения, один из которых катастрофически медленный.

Мы определили несколько семантически идентичных изменений в запросе, что заставляет Oracle постоянно выбирать план быстрого выполнения. Мы боимся ошибки или повреждения данных из-за переключения туда и обратно без видимой причины.

Любые идеи относительно причины такого поведения будут с благодарностью.

Вот мелкие детали:

У нас довольно простой запрос Oracle к четырем простым таблицам схемы. Когда мы выполняем этот запрос, мы получаем совершенно разное время выполнения - если мы выполняем его 20 раз подряд, три или четыре выполнения возвращают данные в течение 4 секунд, другие выполнения занимают более 1000 секунд.

Мы попытались зарегистрировать планы выполнения, и 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'") или в таблице групп ("g.unix_gid is not null"), запрос всегда быстрый, но, конечно, возвращает больше строк. Однако он возвращает 30 000 строк за довольно постоянные 10 секунд (в отличие от 5000 строк за 1000 секунд для плана медленного выполнения более ограниченного запроса).

Соответствующие части схемы, участвующие в запросе:

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")

Ответы [ 2 ]

0 голосов
/ 25 июля 2012

Если вы используете 11g, вы можете использовать Plan Management, чтобы остановить Oracle от переключения планов.

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

0 голосов
/ 02 апреля 2012

Предоставленная вами информация имеет некоторые несоответствия. В этом вопросе вы говорите, что один план использует FAST FULL SCAN, в то время как другой использует RANGE SCAN для того же индекса; но в версии вопроса на сайте dbas вы показываете фактические планы выполнения, и оба используют FAST FULL SCAN в качестве единственной операции на основе индекса. Реальная разница между этими двумя планами, по-видимому, заключается в порядке соединения, где второй порядок требует выполнения более крупных операций в памяти из-за отсутствия условий соединения между первыми таблицами, которые должны быть объединены.

Во всяком случае, у меня есть пара предложений о том, как исследовать это дальше. Одна из идей состоит в том, чтобы активировать событие трассировки 10053 , которое регистрирует все действия оптимизатора, и посмотреть, можно ли сравнить результаты прогонов, которые получают два разных плана. Вывод не очень красивый и может быть трудно понять, но он может дать вам некоторое представление о том, что происходит.

Моя другая мысль состоит в том, что единственное не буквальное значение, которое вы вообще используете в запросе, это SYSDATE, поэтому мне интересно, не вызывают ли изменения во времени изменение арифметики оптимизатора, приводящее к различным планам. Я не уверен, как оптимизатор справляется с SYSDATE. Вы можете попытаться заменить вызовы SYSDATE переменной связывания и установить значение даты в другом коде перед выполнением запроса.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...