"Может кто-нибудь сказать мне, что я делаю неправильно"
С чего начать?
ORA-01555
Это происходит в длительных запросах.Политика согласованности чтения Oracle гарантирует, что последняя запись в наборе результатов будет согласована с первой записью набора результатов.Другими словами, наш запрос не будет возвращать изменения, сделанные в каком-то другом сеансе, которые были зафиксированы после того, как мы выполнили наш запрос.Oracle делает это, подставляя записи из табличного пространства UNDO для любых измененных записей.Когда он не может этого сделать, он выбрасывает исключение SNAPSHOT TOO OLD.Это означает, что у Oracle больше нет старых версий записей, необходимых для обеспечения согласованного чтения.
Распространенная причина, по которой у Oracle больше нет данных, заключается в том, что наш длительный запрос представляет собой цикл курсора PL / SQL, который выдает операторы COMMIT.Как вы должны знать, COMMIT означает конец транзакции, и это освобождает любые блокировки, которые Oracle сохранил для нашего сеанса.Это, очевидно, включает в себя наш интерес к сессиям в табличном пространстве UNDO;Затем Oracle может свободно перезаписывать блоки UNDO, которые содержат данные, необходимые для согласованности чтения.
В вашем случае операторы COMMIT являются неявными, которые заключают в себе любой оператор DDL - включая ANALYZE.Это может не иметь значения, но кажется, что кто-то обновляет таблицу SCENARIOS, пока ваша программа работает, вероятный случай чего-то, что занимает несколько дней.
Использование ANALYZE
Этоэто плохо по нескольким причинам.Во-первых, это давно устарело: вы используете 10g, вам нужно использовать DBMS_STATS для сбора статистики .Но подождите, это еще не все.
Сбор статистики - это не то, что следует делать слишком часто.В большинстве систем статистика достигает плато стабильности, на котором они достаточно точны, даже когда им несколько месяцев.Поэтому частый сбор статистики в лучшем случае является пустой тратой времени.Это может быть гораздо хуже: существует риск, что новая статистика порождает менее эффективный план, чем текущий.Так что на самом деле сбор статистики должен осуществляться контролируемым образом.Одним из преимуществ DBMS_STATS является то, что мы можем настроить его для отслеживания скорости изменений, применяемых к нашим таблицам, и собирать статистику только тогда, когда они достигают определенной устаревания. Узнайте больше.
Конечно, вы используете ANALYZE только для того, чтобы получить актуальное использование пространства для индексов, что подводит меня к третьему пункту:
Безумие
Вы выбираете каждую строку всех таблиц, которые вас интересуют, и суммируете фактический размер всех их столбцов, с - если я правильно понял - отдельным запросомдля каждого столбца.Это безумие.
Oracle предоставляет представления, которые показывают объем пространства, используемого данной таблицей.USER_SEGMENTS должно быть достаточно, хотя USER_EXTENTS также доступна.SEGMENT_NAME - это индекс или имя таблицы.Суммирование столбца БАЙТЫ даст вам точный размер занимаемой площади каждой таблицы.
Конечно, некоторые из этих выделенных экстентов будут пустыми, поэтому вы можете подумать, что эти цифры будут немного завышены.Но:
- Распределенные экстенты на самом деле представляют собой более точную картину использования пространства, поскольку она учитывает пространство, которое удерживается столом.
- Любая предполагаемая потеря "точности" будет возмещаться в запросах, которые будут выполняться в считанные секунды, а не дни.
- После этого запросы вернут позицию сейчас а не меняющаяся картина использования пространства в течение трех дней, поэтому цифры гораздо полезнее.
", но вся мотивация написания всего этого PL /Сценарий SQL должен был получить АКТУАЛЬНОЕ НЕ ВЫДЕЛЕННОЕ ПРОСТРАНСТВО "
Хорошо, давай займемся этим.Основная проблема с вашим скриптом в том, что он решает проблемы с RBAR;на самом деле хуже, чем это, RBARBACТаким образом, вы выдаете матрицу запросов, по одному для каждого столбца каждой строки таблицы.SQL является основанным на множестве языком, и он будет работать намного лучше, если мы будем рассматривать его как таковой.
Эта процедура собирает динамический запрос, который собирает один SELECT, чтобы получить общий размер и количество записей для данной таблицы.
create or replace procedure get_table_size
( p_tabn in user_tables.table_name%type
, p_num_rows out pls_integer
, p_tot_size out pls_integer )
is
stmt varchar2(32767) := 'select count(*), sum(';
n_rows pls_integer;
n_size pls_integer;
begin
for r in ( select column_name, data_type, column_id
from user_tab_columns
where table_name = p_tabn
order by column_id)
loop
if r.column_id != 1
then
stmt := stmt ||'+';
end if;
stmt := stmt || 'nvl(';
if r.data_type in ('CLOB', 'BLOB', 'BFILE')
then
stmt := stmt || ' dbms_lob.getlength('||r.column_name||')';
else
stmt := stmt || ' vsize('||r.column_name||')';
end if;
stmt := stmt || 'nvl)';
end loop;
stmt := stmt || ') from '||p_tabn;
execute immediate stmt into n_rows, n_size;
p_num_rows := n_rows;
p_tot_size := n_size;
end;
/
Не включает заголовок блока (3 байта на строку), но это вопрос простой арифметики.
Вот оно в действии:
SQL> desc t34
Name Null? Type
----------------------------------------- -------- ----------------------------
SEQ_NUM NUMBER
UNIQUE_ID NUMBER
NAME VARCHAR2(20 CHAR)
LONG_COL CLOB
SQL>
SQL> set timing on
SQL> var n1 number
SQL> var n2 number
SQL> exec get_table_size('T34', p_num_rows=>:n1, p_tot_size=>:n2)
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.89
SQL> print n1
N1
----------
11
SQL> print n2
N2
----------
135416
SQL>
Небольшой стол, возможно, нереально быстрый.Вот больший, без сгустков.
SQL> exec get_table_size('BIG_TABLE', p_num_rows=>:n1, p_tot_size=>:n2)
PL/SQL procedure successfully completed.
Elapsed: 00:00:10.65
SQL> print n1
N1
----------
4680640
SQL> print n2
N2
----------
189919606
SQL>
Истекшее время все еще хорошо, ммм?
Что касается пространства для индексов, аналогичный запрос будет работать, только получая из USER_IND_COLUMNS, чтобы получитьсоответствующие имена столбцов.Я думаю, что это предпочтительнее, чем повторный анализ индексов.Он не будет работать для определения размеров любых индексов TEXT, которые вы можете иметь для столбцов CLOB или BLOB.Для тех, кому нужно использовать CTX_REPORT.INDEX_SIZE () , хотя при этом создается отчет, который вам нужно будет проанализировать, чтобы получить полезные цифры (формат XML может быть полезен в этом отношении).