Декабрь 2005
Дмитрий Безруков
“ФОРС – Центр Разработки”
Сегменты отката в Oracle 9i и 10g
Oracle в версии 9i провозгласил лозунг упрощения своего программного обеспечения (lowering the total cost of ownership (TCO). Возможности, описанные в данной статье, реализованы в рамках этого лозунга.
Любой администратор базы данных (АБД) Oracle знает, что мониторинг и управление сегментами отката – дело не простое. Данная статья посвящена возможностям Oracle9i, позволяющим АБД практически не заботиться о сегментах отката, что значительно упрощает администрирование. В Oracle10g АБД предлагается новое средство, позволяющее пользователю выполнять долговременные выборки из таблиц при одновременной модификации этих таблиц другими пользователями без опасения возникновения ошибок. Эта возможность называется автоматическим управлением отменами транзакций (сокращается как АУО) или по-английски Automatic Undo Management (AUM) также является предметом обсуждения данной статьи.
- Администрирование версионности данных в предыдущих версиях Oracle.
В версиях Oracle до 9i старые версии данных некоторое время хранятся в сегментах отката (rollback segments). В начале своей работы транзакции назначается какой-либо сегмент отката, где сохраняются старые версии данных, измененные в базе этой транзакцией. Во время работы данной транзакции активные экстенты сегмента отката располагаются между головой и хвостом сегмента отката и следовательно не могут быть перезаписаны старыми версиями данных от другой транзакции, назначенной на тот же сегмент отката. После фиксации (commit) транзакции пространство, занимаемое старыми версиями данных, может быть перезаписано старыми версиями данных от другой транзакции в случае, если экстенты сегмента отката, в которых они находятся, располагаются между хвостом и головой. B отличие от Oracle9i средства для удержания старых версий данных в сегментах отката на какое-то время после завершения транзакции отсутствуют.
Первый блок первого экстента называется заголовком сегмента отката и содержит таблицу транзакций и другие управляющие структуры. Максимальное количество активных транзакций, которые могут быть назначены на сегмент отката определяется размером таблицы транзакций, который, в свою очередь, определяется размером блока базы данных.
Новая транзакция назначается на сегмент отката по алгоритму LRU. То есть, выбирается тот сегмент отката, на который была назначена самая старая транзакция. В первую очередь просматриваются сегменты отката, не имеющие работающих транзакций, а в случае отсутствия таковых – содержащие активные транзакции.
Каждые экстент сегмента отката может содержать информацию отката от нескольких транзакций, но один блок не может содержать информацию отката от нескольких транзакций.
Мониторинг и управление сегментами отката
Сегменты отката требуют от АБД значительных трудозатрат. Кроме создания выделенных табличных пространств, необходимо создать несколько сегментов отката, определить для каждого оптимальные размер экстента и их количество. Необходимо регулярно осуществлять мониторинг сегментов отката, и в случае необходимости, изменять количество и другие параметры сегментов отката. Кроме того, для длинных транзакций обычно предусматриваются выделенные сегменты отката (set transaction use rollback segment), которые также необходимо обслуживать.
АБД также имеет альтернативы использования глобальных (public) или локальных (private) сегментов отката. Особо следует отметить необходимость администрирования системного сегмента отката SYSTEM,
Перечислим далее некоторые средства из инструментария АБД, относящиеся к сегментам отката:
Параметры экземпляра: ROLLBACK_SEGMENTS, TRANSACTIONS, TRANSACTIONS_PER_ROLLBACK_SEGMENT и MAX_ROLLBACK_SEGMENTS.
Команды SQL: CREATE ROLLBACK SEGMENT, ALTER ROLLBACK SEGEMENT, DROP ROLLBACK SEGMENT.
Представления(views) для мониторинга: DBA_ROLLABCK_SEGS, V$ROLLNAME, V$ROLLSTAT (основная), V$SYSSTAT, V$WAIT_STAT, V$TRANSACTION.
Используемая терминология.
В версиях Oracle до 9i, термин “сегмент отката (rollback segment) является синонимом термина “сегмент отмены (undo segment)”. В версиях Oracle 9i и выше эти термины синонимами уже не являются и обозначают похожие, но различные вещи.
Термины “информация отмены, данные отмены, записи отмены (undo information, undo data, undo records) обозначают данные для управления версиями данных (в Oracle до 9i - это содержимое сегментов отката). Соответственно, управление данными отмены или просто управление отменами (undo management) обозначает управление версиями данных.
- Автоматическое управление версиями в Oracle9i
В этом разделе рассматривается Автоматическое Управление Отменами (АУО) или Automatic Undo Management (AUM) в Oracle9i. В некоторых сообщениях об ошибках в 9i вместо AUM используется термин System Managed Undo (SMU).
Концепции АУО.
В Oracle9i имеется два механизма управления откатами: старый и новый. Старый - традиционный способ описан выше и носит название “Отмены через Сегменты Отката (ОСО)” или Rollback Segment Undo (RSU). Выбор способа определяет АБД при помощи параметра INIT.ORA undo_management. Если undo_management=MANUAL или отсутствует, то выбирается ОСО.
Новый способ АУО, задаваемый undo_management=AUTO,предлагает гибкий с новыми возможностями управления и в то же время очень простой для администрирования механизм. Рассмотрим АУО более подробно.
Для использования АУО АБД должен создать специальное табличное пространство и задать его размер при помощи нового предложения SQL CREATE UNDO TABLESPACE. Кроме того, установить значение статического параметра undo_management в AUTO и указать название этого табличного пространства при помощи динамического параметра undo_tablespace . Аналоги сегментов отката, создаваемые автоматически в undo tablespace и имеющие имена в формате _SYSSMUn$ (где n – натуральное число), во избежание путаницы называются сегментами отмены (undo segments). Сегменты отмены также иногда называют сегментами отката, сгенерированными системой (system generated rollback segments).
При создании undo tablespace в нем создается несколько сегментов отката, но не более 10. Их количество определяется по формуле:
Целая часть ( 1.1 * Sessions / 5 ),
где Sessions – значение параметра Sessions INIT.ORA.
Алгоритм назначения транзакций на сегменты отмены
Алгоритм назначения вновь пришедшей транзакции на сегмент отмены отличен от алгоритмов назначения транзакции на сегмент отката. Рассмотрим его подробнее:
При назначении транзакции на сегмент отмены применяется следующий алгоритм:
- Просматриваются все оперативные сегменты отмены, не имеющие активных транзакций, и из них выбирается сегмент, на который когда-то была назначена самая старая транзакция.
- Если таковых не имеется, то делается попытка включить автономный сегмент отмены (если, конечно, таковой имеется) в оперативный режим и использовать его.
- Если не имеется автономных сегментов, то в случае наличия свободного пространства в undo tablespace создается новый сегмент отмены и на него назначается транзакция.
- Если свободного пространства не имеется, то транзакция назначается на сегмент отмены, уже содержащий активные транзакции. Алгоритм назначения аналогичен алгоритму, реализованному в сегментах отката.
Таким образом, в 9i преобладает тенденция использования одного сегмента отката для каждой транзакции.
Срок хранения информации отмены и распределение пространства в undo tablespace
Внутренняя структура сегмента отмены и алгоритмы работы аналогичны сегментам отката. Главное различие состоит в возможности передачи неактивных экстентов между сегментами отката. Это позволяет реализовать алгоритм истечения срока хранения экстентов в сегментах отката. АБД может задать динамический параметр INIT.ORA undo_retention, обозначающий интервал времени в секундах, в течение которого будет храниться информация отмены (экстенты сегментов отмены), то есть не будет перезаписываться данными отмены от активных транзакций. Это означает псевдо-гарантированный интервал времени, в течение которого можно восстановить модифицированные данные базы. В 9i разработан специальный пакет, DBMS_FLASHBACK (рассматривается ниже), дающий возможность извлекать данные из снимков базы данных. Каждый снимок – данные базы, модифицированные зафиксированными транзакциями на моменты времени в течении предыдущих undo_retention секунд. Но почему же все-таки псевдо-гаранированный интервал? Да потому, что ретроспективное извлечение данных гарантируется только, если в undo tablespace отведено достаточно место. В противном случае, неактивные экстенты будут использоваться повторно, даже если срок хранения данных отмены в этих экстентах не истек. Поэтому рекомендуемый размер undo tablespace в зависимости от интенсивности текущих транзакций следует задавать, руководствуясь формулой:
Размер = undo_retention * UBPS + запас,
где undo_retention – значение соответствующего пара;
UBPS – количество блоков, записываемых в undo tablespace в секунду; можно оценить по представлению V$UNDOSTAT (см. ниже);
Запас – плюс блоки для битовой адресации, таблиц транзакций и т.д.
Сегменты отмены переводятся в оперативный режим во время открытия базы данных, о чем делается отметка в ALERT.LOG.
В случае, если транзакции требуется новый экстент для записи информации отмены, применяется следующий алгоритм:
- Анализируется следующий экстент за головой данного сегмента отмены. Если его срок хранения истек, то в него записывается информация отката. Если срок хранения не истек или он содержит хвост сегмента отмены, то проверяется наличие свободных экстентов в undo tablespace, и если имеется хотя бы один свободный, то он добавляется в сегмент отмены и голова продвигается в его первый блок.
- Если свободного места нет, то анализируются следующие за головами неактивные экстенты других сегментов отмены. Первый найденный экстент с истекшим сроком хранения удаляется из содержащего его сегмента и добавляется в данный сегмент отмены и голова продвигается в него. При этом посылается сообщение фоновому процессу SMON (см. ниже).
- Если в других сегментах свободных экстентов не найдено, то делается попытка добавить в файл пространство, если, конечно, в файле задан режим AUTOEXTEND ON и есть возможность для расширения. В случае успеха, в undo tablespace добавляется свободное пространство, из которого выделяется экстент и добавляется в сегмент.
- Если нельзя добавить пространство, то выдается ошибка ORA-01562 failed to extend rollback segment.
За сжатие/удаление сегментов отмены отвечает фоновый процесс SMON. Каждые 12 часов SMON делает попытку удаления неактивных экстентов с истекшим сроком хранения из сегментов отмены. Кроме того, если серверный процесс вынужден при обработке транзакции позаимствовать экстент у другого сегмента, он сообщает об этом процессу SMON, который для предотвращения избыточной нагрузки на undo tablespace сжимает сегменты отмены, возвращая экстенты с истекшим сроком хранения в пул свободных экстентов.
Обращение к старым версиям данных будет успешным только тогда, когда эти версии можно восстановить по сегментам отмены/отката. Если неактивный экстент сегмента отмены/отката, необходимый для получения данной старой версии данных переписывается новой информацией отмены, то при обращении к данной версии возникает ошибка ORA-01555 Snapshot too old, rollback segment too small.
Следует также отметить, что в случае, если срок хранения какого-либо экстента истек, но его содержание не было затерто другой информацией отмены, то этот экстент может участвовать в процессе восстановления старых версий данных.
- Различия между сегментами отката и сегментами отмены
В терминологии Oracle9i сегменты отката и сегменты отмены, хотя и используют практически одни и те же алгоритмы функционирования, синонимами не являются, так как имеют следующие различия:
- Сегменты отката
создаются, уничтожаются, переводятся в оперативный/автономный режимы и сжимаются администратором при помощи соответствующих предложений DDL языка SQL. На сегменты отмены эти предложения не действуют. Аналоги вышеуказанных действий проводятся в Oracle9i, автоматически базируясь на оперативной ситуации в системе.
- Если в сегменте отката все экстенты активны и необходимо выделить дисковое пространство, то новый экстент выбирается из пула свободных экстентов табличного пространства и выдается ошибка, если таковых не имеется. Экстент в сегмент отмены может быть добавлен также, как и в сегмент отката и, кроме того, может быть перераспределен неактивный сегмент из другого сегмента отмены. Этим достигается оптимальное использование дискового пространства в undo tablespace.
- Сегменты отмены
позволяют режим использования срока хранения (retention period), когда имеется возможность выборки предыдущих версий данных (см. ниже). При использовании сегментов отката такая возможность отсутствует.
- Для каждого сегмента отката АБД определяет параметры хранения, а именно размер экстента и их выделяемое и максимальное количество. Для сегментов отмены все определяется автоматически.
- Автоматическое сжатие сегментов отката производится на базе заданного АБД параметра optimal фразы storage. Сжатие сегментов отмены проводится всегда автоматически по другим критериям.
- Оперативные (online) сегменты отката могут располагаться в нескольких табличных пространствах. Эти табличные пространства могут иметь любые допустимые распределения пространства. Оперативные сегменты отмены могут располагаться только в одном (undo_tablespace). Это табличное пространство определяется как locally managed automatic allocation, то есть размер экстента не задается.
- Набор представлений (views) для мониторинга различен. Сегменты отмены доступны для мониторинга через те же представления, что и сегменты отката, плюс несколько дополнительных представлений.
- Технические детали АУО
В этом разделе представлены некоторые важные технические моменты использования АУО.
Нельзя использовать одновременно АУО и ОСО в открытой работающей базе данных, хотя в разное время это возможно. Для замены АУО на OCO и обратно необходимо заглушить (shutdown) базу данных и стартовать (startup) с другим значением параметра экземпляра undo_management.
Концепция использования системного сегмента отката SYSTEM сохраняется и при АУО. Методы администрирования этого сегмента остаются такими же, как и ранее (следует отметить, что SYSTEM не может быть переключен в автономный (offline) режим).
В случае, если мы используем АУО, то есть задан undo_management=AUTO, то при наличии в INIT.ORA параметров, связанных с ОСО, таких как rollback_segments, transactions_per_rollback_segment и т.д., они игнорируются. И наоборот, если undo_management=MANUAL, то параметры АУО (undo_tablespace и др.) также не принимаются во внимание.
Undo tablespace может быть создано как предложением CREATE DATABASE во время создания базы данных, так и в любое другое время предложением CREATE UNDO TABLESPACE при открытой базе данных. Важно задать правильный размер файлов в этом табличном пространстве. Это влияет на выполнение длинных транзакций и на реальный срок хранения версий данных в базе. В любом случае, чем больше места, тем лучше. DROP TABLESPACE <название> удаляет undo tablespace. При использовании этого предложения неявно подразумевается фраза including content.
Undo tablespace не может содержать данных других типов, кроме сегментов отмены и отката. Таким образом, это табличное пространство нельзя использовать для хранения таблиц, временных сегментов и т.д.
В базе данных может существовать несколько undo tablespaces, хотя в каждый момент времени только одно из них может быть активным, то есть работать с данными отмены. Для переключения между ними следует использовать динамический параметр undo_tablespace. Для переключения можно изменить название табличного пространства в INIT.ORA и затем перезапустить базу данных (shutdown/startup), либо воспользоваться предложением ALTER SYSTEM SET undo_tablespace=<название>. Перевести текущее активное undo tablespace в неактивный режим, то есть прекратить использование сегментов отмены, расположенных в этом табличном пространстве, можно при помощи предложения ALTER SYSTEM SET undo_tablespace=’’. Следует также отметить, что после выполнения этого предложения АУО более не поддерживается и работает только сегмент отката SYSTEM.
При работе в режиме АУО база данных будет открываться и в случае, если undo tablespace вообще не задано. В этом случае доступен только сегмент отката SYSTEM. Его использование возможно только в случае операций DML над табличным пространством SYSTEM. В такой ситуации можно создать новое undo tablespace, активизировать его предложением ALTER SYSTEM SET undo_tablespace=<название> и продолжать работу со всеми другими табличными пространствами в нормальном режиме.
- Совместимость АУО c прикладными системами, разработанными для предыдущих версий Oracle
Как уже упоминалось выше, все DDL-предложения с сегментами отмены запрещены. Но тогда, как же будут работать прикладные системы, использующие такие предложения, как, например, set transaction use rollback segment <название>? Для этого в 9i предусмотрен специальный динамический параметр undo_suppress_errors. Если он установлен в true, то все DDL-предложения, работающие с сегментами отката, выдают успешный код возврата. Рассмотрим следующий пример в предположении, что undo_management=auto:
SQL> alter system set undo_suppress_errors=false; -- DDL запрещены
rem
System altered.
SQL> create rollback segment BIGRBS tablespace UNDOTBS;
create rollback segment BIGRBS tablespace UNDOTBS
*
ERROR at line 1:
ORA-30019: Illegal rollback Segment operation in Automatic Undo mode
SQL> commit;
Commit complete.
SQL> set transaction use rollback segment BIGRBS;
set transaction use rollback segment BIGRBS
*
ERROR at line 1:
ORA-30019: Illegal rollback Segment operation in Automatic Undo mode
rem
SQL> alter system set undo_suppress_errors=true; -- DDL разрешены
System altered.
SQL> create rollback segment BIGRBS tablespace UNDOTBS;
Rollback segment created.
SQL> set transaction use rollback segment BIGRBS;
Transaction set.
. . . . . . . . .
SQL> drop rollback segment BIGRBS;
Rollback segment dropped.
Если параметр undo_suppress_errors не задан, то по умолчанию он принимает значение false. Поэтому перед запуском прикладной системы на Oracle 9i имеет смысл установить этот параметр в true.
Мониторинг АУО
Можно проводить мониторинг сегментов отмены, используя те же представления, что и для мониторинга сегментов отката (см. ранее). Кроме того, существуют несколько новых представлений. Рассмотрим их подробнее.
V$UNDOSTAT – содержит статистики для мониторинга и регулировки размера undo tablespace. Это представление также полезно при регулировке сегментов отката. В нем представлены статистики потребления пространства в сегментах, конкуренция транзакций за сегменты и длина выдаваемых пользователем запросов. Каждая строка представления содержит статистики за интервал времени (Begin_time, End_time), обычно 10 минут. Каждая строчка в преставлении хранится в течение 24 часов. При загрузке базы данных содержимое представления обнуляется. Столбцы таблицы кроме Begin_time/End_time:
- UndoBlcks
– количество блоков отмены/отката записанных за интервал. Используется для подсчета интенсивности потребления пространства в undo tablespace.
- MaxConcurrency –
максимальное количество транзакций, выполнявшихся одновременно на данном интервале.
- TxnTotal
– общее число транзакций за данный интервал.
- MaxQueryLength –
максимальная длина запроса в секундах за интервал.
- SsOldErrCnt –
количество ошибок ORA-01555 (Snapshot too old), возникших за данный интервал. Если этот столбец содержит ненулевые значения, то нужно увеличить undo_retention и, возможно, размер табличного пространства.
- UnxpStealCnt –
число попыток получения экстента с не истекшим сроком хранения у другого сегмента отмены за интервал.
- UnxpBlkRelCnt
– число блоков с неистекшим сроком хранения, перераспределенных на другие сегменты отмены за интервал.
- UnxpBlkReuCnt -
число блоков с неистекшим сроком хранения, используемых транзакциями повторно за интервал.
- ExpStealCnt -
число попыток получения экстента с истекшим сроком хранения у другого сегмента отмены за интервал.
- ExpBlkRelCnt -
число блоков с истекшим сроком хранения, перераспределенных на другие сегменты отмены за интервал.
- ExpBlkReuCnt
- число блоков с истекшим сроком хранения, использованных за интервал повторно в своих сегментах отмены.
- NoSpaceErrCnt –
количество раз, когда Oracle не может найти места для генерации информации отмены из-за того, что сегменты отмены занимают все табличное пространство, и все экстенты всех сегментов заняты активными транзакциями. При увеличении значений нужно добавить пространства в undo tablespace.
Для того, чтобы посчитать интенсивность потребления пространства в undo tablespace в блоках в секунду (UBPS) на интервале времени, то нужно выполнить что-то вроде:
select Sum(UndoBlcks) / (sum(End_time–Begin_time)*24*60*60)
‘Блоки|в сек.’
from V$UNDOSTAT
where Begin_time >= to_date(<время_1>) or End_time <= <Время_2>;
Oracle Enterprise Manager Console (аналог DBA Studio в 8i), основываясь на этом представлении, выводит графические оценки пространства в undo tablespace для максимально и средней скорости потребления данных отмены. Также выводится значение параметра undo_retention. Для получения этих графиков необходимо пройти Network->Databases->Название->Configuration->Undo.
Представление DBA_UNDO_EXTENTS показывает дату и время фиксации последней транзакции в экстенте, а также статус истечения срока хранения (EXPIRED/UNEXPIRED/ACTIVE) для каждого сегмента и экстента в undo tablespace.
- Автоматическое управление версиями в Oracle 10g.
Работа с сегментами отката в Oracle 10g не отличается от Oracle 9i, кроме одного, но очень существенного новшества. Как отмечалось в п.2.1.2 срок хранения старых версии данных в сегментах отката, задаваемых параметром init.ora undo_retention в Oracle 9i носит рекомендательный характер и не гарантирует заданного этим параметром срока в случае отсутствия свободного места в табличном пространстве для сегментов отмены (естественно, речь идет о работе в режиме АУО). Таким образом, отсутствует гарантированная защита от ошибки ORA-1555. При получении отчета, требующего больших временных затрат, необходимо запирать участвующие таблицы, защищая их от модификации другими пользователями на время выполнения отчета; либо предоставив большое дисковое пространство для табличного пространства отмены, что теоретически не может гарантированно предотвратить ORA-1555, а практически требует значительного опыта и может вызвать нежелательные эффекты.
Oracle 10g теперь позволяет гарантировать, что в течение срока undo_retention старые версии даны сохраняются от перезаписи, и ошибка ORA-1555 не возникнет. Технически это реализовано через новый параметр текущего табличного пространства отмены retention.
Рассмотрим пример. Предположим, что необходимо запустить отчет, который может выполняться три часа максимум. Для предотвращения возникновения ошибки ORA-1555 необходимо выполнить следующие действия:
alter system set undo_retention=10800;
alter tablespace UNDOTBS1 retention guarantee;
-- запустить в другом сеансе выполнение отчета,
-- подождать его завершения и вернуть обычные
-- значения параметров.
alter tablespace UNDOTBS1 retention noguarantee;
alter system set undo_retention=900;
Посмотреть текущие установки для предоставления гарантий срока хранения для табличного пространства можно в столбце Retention таблицы DBA_TABLESPACES, который может принимать значения GUARANTEE и NOGUARANTEE для табличных пространств отмены и NOT APPLY для остальных.
Следует также отметить, что установка достаточно большого гарантированного срока хранения также может иметь смысл для восстановления вероятных ошибок пользователей, неверно модифицировавших данные с помощью операторов DML. В этом случае возможно с помощью ретроспективных запросов (flashback queries) гарантированного просмотреть старые версии и восстановить ошибочно модифицированные данных в течение undo_retention секунд с момента совершения ошибки пользователем.
Возникает резонный вопрос: “А почему-бы не установить большой гарантированный срок хранения, скажем, неделю, для штатной эксплуатации прикладной системы?” Действительно, в этом случае можно не заботясь об ошибках выполнять любые долговременные отчеты и исправлять ошибки пользователя. Однако, следует помнить, что чем интенсивнее текущие транзакции, тем больше места они требуют табличном пространстве отмены. Если при установленном гарантированном сроке хранения кончилось пространство для отмены, а гарантированное время еще не истекло, то модифицирующие базу данных сессии будут получать ошибки о нехватке места для записи информации в табличное пространство отката. Для оценки места, требуемого для табличного пространства отката, следует пользоваться средствами, описанными в п.2.2.2 выше. Пользуясь представлением V$UNDOSTAT можно оценить потребление пространства сегментами отката и примерно посчитать место на дисках, требуемое для табличного пространства отмены для хранения версий за заданный период времени. Здесь следует помнить о запланированных и незапланированных массовых обновлениях базы данных. Конечно, при массовых обновлениях следует отключать параметры гарантированного срока хранения.
- Литература
Кроме стандартной документации по Oracle9i, которая содержит необходимые сведения, лучше всего пользоваться metalink.oracle.com. В этом разделе приводятся координаты некоторых замечаний и бюллетеней с этого сайта. Поиск этих материалов не составляет труда. Нужно просто набрать соответствующий номер в строке поиска.
- В замечании metalink 204334.1 разбираются особенности параметров FLASHBACK_SCN и FLASHBACK_TIME утилиты export.
- Рекомендую замечание metalink №135217.1. Много хороших примеров работы с сегментами отката в режиме АУО и с сегментами отмены в OCO. Разбираются особенности сегментов отката, создаваемых вручную в undo tablespace. Может помочь в сложных случаях.
- В замечании metalink 150216.1 рассматривается хитрый случай, когда из-за параметра undo_suppress_errors установленного в TRUE, создается ситуация, которая может ввести в заблуждение АБД.
- Замечание 153042.1 показывает ситуацию, когда неверные установки параметров undo_management и undo_tablespace могут вызвать сбой во время запуска базы данных.
- Замечание 135053.1 дает пример создания undo tablespace во время создания базы данных.
- Странная ошибка при активизации undo tablespace, находящегося в автономном режиме, объясняется в замечании 149685.1
- Бюллетень 157278.1 (большой файл в формате PDF) описывает АУО в целом. К сожалению, содержит ошибки и неточности.
|