Я разрабатываю DWH на Oracle 11g. У нас есть несколько больших таблиц (250+ миллионов строк), разделенных по значению. Каждый раздел назначается другому источнику питания, и каждый раздел не зависит от других, поэтому их можно загружать и обрабатывать одновременно.сбор параллельной статистики по таблице разделенных Oracle 11g
Распределение данных очень неравномерно, у нас есть раздел с миллионами строк и разделы с не более ста строк, но я не выбрал схему разбиения, и, кстати, я не могу ее изменить.
Учитывая объем данных, мы должны заверить, что каждый раздел имеет всегда актуальную статистику, потому что, если последующие разработки не имеют оптимального доступа к данным, они будут длиться вечно.
Таким образом, для каждого параллельного ETL потока, мы
- Обрезать раздел
- Загрузка данных из промежуточной области с
SELECT /*+ APPEND */ INTO big_table PARTITION(part1) FROM temp_table WHERE partition_colum = PART1
(после этого у нас есть прямой путь и мы не блокировать всю таблицу)
- Мы собираем статистику для измененного раздела.
На первом этапе проекта, мы использовали стратегию APPROX_GLOBAL_AND_PARTITION
и работал как шарм
dbms_stats.gather_table_stats(ownname=>myschema,
tabname=>big_table,
partname=>part1,
estimate_percent=>1,
granularity=>'APPROX_GLOBAL_AND_PARTITION',
CASCADE=>dbms_stats.auto_cascade,
degree=>dbms_stats.auto_degree)
Но мы имели тот недостаток, что, когда мы загрузили небольшой раздел, то APPROX_GLOBAL часть была (все еще намного быстрее GLOBAL), а для небольшого раздела у нас было, например, 10 секунд загрузки и 20 минут статистики.
Так мы предложили, чтобы переключиться на INCREMENTAL STATS особенность 11g, что означает, что вы не указали раздел, который вы модифицировали, вы оставляете все параметры в автоматическом, и Oracle делает это волшебство, автоматически понимание какие разделы (разделы) были затронуты. И это действительно работает, мы действительно ускорили небольшой раздел. После включения функции, вызов стал
dbms_stats.gather_table_stats(ownname=>myschema,
tabname=>big_table,
estimate_percent=>dbms_stats.auto_sample_size,
granularity=>'AUTO',
CASCADE=>dbms_stats.auto_cascade,
degree=>dbms_stats.auto_degree)
уведомление, что вы не пропустите раздел больше, и вы не указали образец процента.
Но у нас есть недостаток, может быть, еще хуже, чем предыдущий, и это коррелирует с высоким уровнем параллелизма, который у нас есть.
Предположим, что у нас есть 2 больших раздела, которые запускаются в одно и то же время, они закончат фазу загрузки почти одновременно.
Первая нить завершает инструкцию вставки, фиксирует и запускает сбор статистических данных. В процедуре статистики есть два измененных раздела (это правильно, один заполнен, а второй усечен, с текущей транзакцией), корректно обновляет статистику для обоих разделов.
В конце концов второй раздел заканчивается, собирает статистику, он видит, что все разделы уже обновлены, и ничего не делает (это НЕ правильно, потому что второй поток передал данные тем временем).
Результат:
PARTITION NAME | LAST ANALYZED | NUM ROWS | BLOCKS | SAMPLE SIZE
-----------------------------------------------------------------------
PART1 | 04-MAR-2015 15:40:42 | 805731 | 20314 | 805731
PART2 | 04-MAR-2015 15:41:48 | 0 | 16234 | (null)
и следствием является то, что я время от времени брать на себя в не оптимальных планов (что означает убийство сессии, обновить вручную статистику, вручную запустить прецессировать снова).
Я пробовал даже поставить эксклюзивный замок на сбор, поэтому не более одного потока можно сразу собрать статистику по одной и той же таблице, но ничего не изменилось.
IMHO это странное поведение, потому что процедура статистики, во второй раз, когда она вызывается, должна проверять последнюю фиксацию на втором разделе и должна видеть, что она новее, чем последнее время сбора статистики. Но похоже, что этого не происходит.
Я что-то не так? Это ошибка Oracle? Как я могу гарантировать, что все статистические данные всегда обновляются с включенной функцией инкрементной статистики и высоким уровнем параллелизма?
Взгляните на 'DBA_TAB_PARTITIONS' и' begin dbms_stats.flush_database_monitoring_info; конец; '. Кажется, что некоторые грязные чтения продолжаются с данными изменения таблицы - несколько сеансов видят друг друга в незанятых вставках, и один сеанс может очистить эти данные для всех сеансов. Я не думаю, что это специфично для инкрементной статистики. Это может помочь вставить и удалить одну фиктивную строку прямо перед вызовом 'DBMS_STATS', чтобы помочь принудительно собрать.Я бы хотел опубликовать больше, но у меня нет достаточно времени для полного ответа прямо сейчас. –
К сожалению, у меня нет привилегий DBA, и я мот даже владелец стола. docs, кстати, говорят, что «поскольку процедуры GATHER _ * _ STATS внутренне скрывают информацию мониторинга, нет необходимости запускать эту процедуру перед сбором статистики». Я пытаюсь собрать только статистику уровня раздела (которая работает) и периодически обновлять глобальную сеть, чтобы обойти проблему, пока я не найду окончательное решение. – Francesco
Вы должны предложить более подробную информацию. Когда начинается точно ваша вставка? до или после появления подозрительной стальной статистики? какой из них заканчивается первым вставкой? hou много времени берет коммиты? сколько времени занимает статистика статистики воровства статистики? Может быть, сбор на первом разделе происходит во время второй сессии? –