Запрос:
Код: Выделить всё
SELECT a57.IDDEF as IDDEF, a57.IDCARD as ID, a57.VAL as F57, a88.VAL as F88, a112.VAL as F112, a113.VAL as F113
FROM VAL_STR a57, VAL_BOOL a88, VAL_STR a112, VAL_STR a113
WHERE a57.IDDEF=20 and a57.idfield=57 and a88.IDDEF=20 and a88.idfield=88 AND
a88.IDCARD=a57.IDCARD AND a88.VAL=1 and
a112.IDDEF=20 and a112.idfield=112 AND a112.IDCARD=a57.IDCARD and
a113.IDDEF=20 and a113.idfield=113 AND a113.IDCARD=a57.IDCARD and
ORDER BY a57.VAL
Код: Выделить всё
PLAN SORT (JOIN (a88 INDEX (VAL_BOOL_IDX5,VAL_BOOL_IDX1),a113 INDEX (VAL_STR_IDX5),a112 INDEX (VAL_STR_IDX5),a57 INDEX (VAL_STR_IDX5)))
Prepare time = 0ms
Execute time = 16ms
Avg fetch time = 16.00 ms
после обновления статистки с планом:
Код: Выделить всё
PLAN JOIN (a57 INDEX VAL_STR_IDX1),a113 INDEX (VAL_STR_IDX5),a112 INDEX (VAL_STR_IDX5),a88 INDEX (VAL_BOOL_IDX5,VAL_BOOL_IDX1))
Prepare time = 0ms
Execute time = 32s 922ms
Avg fetch time = 32s 922.00 ms
Время выборки увеличилось более чем в 2 тысячи раз!!!
В таблице VAL_BOOL 52 072 записей, в таблице VAL_STR 408 262.
IBExpert показывает, что в первом случае индексированных чтений было 4, во втором >52000 (не индексированных чтений нет). Предполагаю, отсюда и время выполнения.
Результат выборки - одна запись.
Никаких других действий с базой (в целях чистоты эксперимента) не проводились.
Попытка обсуждения похожей проблемы была предпринята на этом форуме в августе прошлого года (см. тему "Firebird - изменился план запроса после backup/restore"), но кроме фразы Дмитрия Кузьменко "бывает такое. кардинальность таблиц после b/r изменилась. некая таблица стала "плотнее", т.е. меньше фрагментирована, наверняка.",
которая никак проблему не разъясняет (во всяком случае для меня), по существу вопроса ничего сказано не было (тема быстро перешла на обсуждение самого запроса, тем и закончилась).
Но вопрос остался: "что делать?"
Я не могу вручную подставлять нужный план из-за того, что приложение генерит великое множество вариантов запросов (похожих на представленный) и угадать (знать) порядок следования индексов в очередном варианте запроса, чтобы он работал быстро просто невозможно.
Перестройка запроса (допустим, в одном из экспериментов в запросе применялись явные join) ни к каким изменениям не приводит, результат один и тот же (формулируя проблему в этой базе): до обновления статистики индексов выборка выполняется быстро, после обновления - тормоза.
А решается ли в моем случае эта проблема вообще? Что-то не получается.
Подобные запросы успешно работают с 2003 года в различных базах и только в этой обнаружилась проблема.
IBAnalist показывает, что в базе много "плохих" индексов. Но после обновления статистики индексов как они были "плохими" так и остаются. И как в насмешку рекомендует (kdv, никоим образом не хочу задеть очень даже достойную программу, просто констатация факта):
Но именно после обновления статистики и происходит появление неоптимизированного плана. Впрочем, "не оптимизированный" и "не корректный", вполне возможно, разные вещи."Обнаружено, что в базе данных есть индексы (32), у которых устарела информация о статистике. Это может привести к формированию оптимизатором некорректных планов запросов. Рекомендуется периодически выполнять команду set statistics index <index_name> для каждого не уникального индекса...".