Несоответствие диапазона дат Oracle - PullRequest
1 голос
/ 16 ноября 2011

Я выполняю довольно большой запрос для определенного диапазона дат. Запрос занимает около 30 секунд, КРОМЕ, когда я делаю диапазон 10/01 / 2011-10 / 31/2011. По некоторым причинам этот диапазон никогда не заканчивается. Например, 01/01 / 2011-01 / 31/2011 и почти все остальные диапазоны заканчиваются в ожидаемое время.

Кроме того, я заметил, что создание меньших диапазонов, например, недели, занимает больше времени, чем большие диапазоны.

1 Ответ

2 голосов
/ 17 ноября 2011

Когда Oracle собирает статистику для таблицы, она записывает низкое и высокое значения в столбец даты и использует их для оценки мощности предиката.Если вы создадите гистограмму в столбце, она соберет более подробную информацию о распределении данных в столбце.В противном случае оптимизатор Oracle на основе затрат (CBO) примет равномерное распределение.

Например, если у вас есть таблица с 1 миллионом строк и столбцом DATE с низким значением 1 января 2001 года и высоким значением 1 января 2011 года, предполагается, что приблизительно 10% данных находится в диапазоне с 1 января 2001 г. по 1 января 2002 г., и примерно 0,027% данных будут получены с некоторого времени 3 марта 2008 г. (1 / (10 лет * 365 дней в году + високосные дни).

Пока ваши запросы используют даты из известного диапазона, оценки кардинальности оптимизатора, как правило, довольно хорошие, поэтому его решения о том, какой план использовать, довольно хороши. Если вы выходите за рамки верхнего или нижнегооценки все еще довольно хороши, потому что оптимизатор предполагает, что, вероятно, есть данные, которые больше или меньше, чем он видел при выборке данных для сбора статистики. Но когда вы слишком далеко от диапазона, который ожидает статистика оптимизаторавидите, оценки кардинальности оптимизатора слишком сильно расходятся, и в итоге выбирается плохаяп.В вашем случае до обновления статистики максимальное значение, которое ожидал оптимизатор, было, вероятно, 25 или 26 сентября 2011 года. Когда ваш запрос искал данные за октябрь 2011 года, оптимизатор, скорее всего, ожидал, что запрос вернется.очень мало строк и выбрали план, который был оптимизирован для этого сценария, а не для большего количества строк, которые были фактически возвращены.Это привело к тому, что план стал намного хуже, учитывая фактический объем возвращаемых данных.

В Oracle 10.2, когда Oracle выполняет жесткий анализ и генерирует план для запроса, который загружается в общий пул, онпросматривает значения переменных связывания и использует эти значения для оценки количества строк, которые запрос возвратит, и, следовательно, наиболее эффективного плана запроса.После создания плана запроса и до его устаревания из общего пула последующие выполнения того же запроса будут использовать один и тот же план запроса независимо от значений переменных связывания.Конечно, в следующий раз, когда запрос будет подвергнут жесткому анализу, поскольку план устарел, Oracle будет смотреть и, скорее всего, увидит новые значения переменных связывания.

Просмотр переменной привязки не являетсяособенно популярная функция (Adaptive Cursor Sharing в 11g лучше на ), потому что администратору БД или разработчику очень трудно предсказать, какой план будет использоваться в любой конкретный момент, потому что выникогда не убедитесь, что значения переменных связывания, которые оптимизатор увидел во время жесткого анализа, соответствуют значениям переменных связывания, которые вы обычно видите.Например, если вы ищете в диапазоне 1 дня, индексное сканирование почти наверняка будет более эффективным.Если вы выполняете поиск в диапазоне 5 лет, сканирование таблицы почти наверняка будет более эффективным.Но в итоге вы используете тот план, который был выбран во время жесткого анализа.

Скорее всего, вы можете решить проблему, просто обеспечив более частый сбор статистики по таблицам, которые часто запрашиваются на основе диапазонов монотонно растущих значений(столбцы даты, безусловно, самый распространенный такой столбец).В вашем случае прошло около 6 недель с момента сбора статистики до того, как возникла проблема, поэтому, вероятно, было бы безопасно обеспечить сбор статистики по этой таблице каждый месяц или каждые две недели, в зависимости от того, насколько затратным является сбор статистики.

Вы также можете использовать процедуру DBMS_STATS.SET_COLUMN_STATS, чтобы явно установить статистику для этого столбца на более регулярной основе. Это требует больше кодирования и работы, но экономит ваше время сбора статистики. Это может быть чрезвычайно выгодно в среде хранилища данных, но, вероятно, излишне в более нормальной среде OLTP.

...