|
Программирование >> Oracle
Разберемся, почему возникают некоторые ошибки в базе данных (в частности, ORA-01555: snapshot too old) и как их предотвратить. Мы уже рассматривали механизм повторного выполнения в главе 4, а теперь затронем ряд специфических проблем. Многие из этих проблем могут выявить разработчики, но исправлять их должен администратор базы данных, поскольку они влияют на весь сервер в целом. Мы начнем с анализа происходящего в ходе фиксации, а затем перейдем к часто задаваемым вопросам и проблемам, связанным с активными журналами повторного выполнения. Что происходит при фиксации? Разработчики должны очень четко понимать, что происходит при выполнении оператора COMMIT. Фиксация транзакции - очень быстрая операция, независимо от размера транзакции. Можно подумать, что чем больше транзакция (т.е. чем больше дан-н1х она затрагивает), тем дольше будет выполняться фиксация. Это неверно. Время выполнения фиксации обычно достаточно стабильно и мало зависит от размера транзакции. Дело в том, что при фиксации не так уж много делается, но эти действия - жизненно важны. Понимая все это, вы сможете делать транзакции настолько большими, как они должны быть. Многие разработчики искусственно ограничивают размер своих транзакций, фиксируя строки группами, а не после выполнения логической единицы работы. Они делают это, исходя из ошибочного предположения, что экономят ресурсы системы; на самом же деле они их транжирят. Если фиксация одной строки требует X единиц времени, а фиксация тысячи строк - тех же X единиц времени, то, выполняя работу так, что 1000 строк фиксируется одним оператором COMMIT, можно сэкономить 999 единиц времени. Фиксируя транзакции только при необходимости (когда транзакция закончена), вы не только повышаете производительность, но и сокращаете конфликты доступа к общим ресурсам (журнальным файлам, внутренним защелкам и т.п.). Простой пример демонстрирует, что короткие транзакции требуют для выполнения больше времени: tkyte@TKYTE816> create table t (x int) ; tkyte@TKYTE816> set serveroutput on tkyte@TKYTE816> declare 2 l start number default dbms utility.get time; 3 begin 4 for i in 1 . . 1000 5 loop 6 insert into t values (1) ; 7 end loop; 8 commit; 9 dbms output.put line 10 (dbms utility.get time-l start hsecs); 11 end; 12 / 7 hsecs PL/SQL procedure successfully completed. tkyte@TKYTE816> declare 2 l start number default dbms utility.get time; 3 begin 4 for i in 1 . . 1000 5 loop 6 insert into t values (1) ; 7 commit ; 8 end loop; 9 dbms output.put line 10 (dbms utility.get time-l start hsecs); 11 end; 12 / 21 hsecs PL/SQL procedure successfully completed. В данном случае потребовалось в три раза больше времени (в вашем случае результат может быть другим). При одновременном выполнении этого кода несколькими пользователями, слишком часто фиксирующими транзакции, скорость работы существенно уменьшается. Мной было показано, как не использование связываемых переменных и частое выполнение жесткого разбора заметно снижает параллелизм из-за конфликтов доступа к библиотечному кэшу и дополнительной нагрузки на процессор. Даже с учетом использования связываемых переменных слишком частое выполнение мягких разборов существенно увеличивает расходы ресурсов. Операции надо выполнять, только когда это действительно необходимо, а фиксация транзакции - такая же операция, как и разбор. Размер транзакций должен определяться требованиями приложения, а не ошибочными попытками сэкономить ресурсы базы данных. Так почему же продолжительность фиксации почти не зависит от размера транзакции? До начала фиксации изменений в базе данных, мы уже сделали все самое сложное - изменили данные, так что 99,9 процента работы сделано. Например, уже были выполнены следующие операции: в области SGA сгенерированы записи сегмента отката; в области SGA сгенерированы измененные блоки данных; помещены в буфер журнала повторного выполнения в области SGA данные по- вторного выполнения для перечисленных выше изменений; в зависимости от размера трех предгдущих фрагментов данных и прошедшего времени, часть их может уже быть сброшена на диск; установлены все необходимые блокировки. При выполнении фиксации осталось сделать следующее. Сгенерировать номер системного изменения (SCN - System Change Number) для транзакции. Процессу LGWR надо записать на диск все оставшиеся записи из буфера журнала повторного выполнения, а также записать в активные файлы журнала повторного выполнения номер SCN. Именно этот шаг и является фактической фиксацией. Если этот шаг выполнен, - транзакция зафиксирована. Если запись транзакции удалена, значит, транзакция зафиксирована. Соответствующая запись в представлении V$TRANSACTION исчезнет. Все блокировки, удерживаемые транзакцией, снимаются, и все сеансы, ожидавшие в очередях снятия этих блокировок, могут продолжить работу. Многие измененные транзакцией блоки данных будут повторно обработаны и очищены в быстром режиме, если они еще находятся в буферном кэше. Как видите, для обработки оператора COMMIT надо сделать очень немного. Самая продолжительная операция выполняется процессом LGWR, поскольку связана с физическим вводом/выводом. Время работы процесса LGWR при этом будет в рамках допустимого (ограничено), поскольку он периодически сбрасывает на диск содержимое буфера журнала повторного выполнения. Процесс LGWR не буферизует все изменения по ходу их выполнения. Он постепенно сбрасывает содержимое буфера журнала повторного выполнения в фоновом режиме по мере его заполнения. Так делается, чтобы при выполнении оператора COMMIT не пришлось очень долго ждать разового сброса всей сгенерированной информации повторного выполнения. Процесс LGWR выполняет этот сброс постоянно: каждые три секунды; при заполнении буфера журнала на треть или при записи в него 1 Мбайт информации; при фиксации транзакции. Так что, даже если транзакция выполняется долго, большая часть сгенерированной информации повторного выполнения уже сброшена на диск еще до фиксации. С другой стороны, однако, при фиксации необходимо дождаться, пока вся оставшаяся в буфере сгенерированная информация повторного выполнения не будет сохранена на диске. Таким образом, обращение к процессу LGWR выполняется синхронно. Хотя процесс LGWR и может использовать асинхронный ввод/вывод для параллельной записи в файлы журналов повторного выполнения, транзакция будет ждать, пока процесс LGWR не закончит все записи и не получит подтверждение записи всех данных на диск. Если вам еще не знаком упомянутый выше номер SCN - это простой механизм отслеживания времени, используемый сервером Oracle для упорядочения транзакций и возможности восстановления после сбоя. Он также используется для обеспечения согласованности по чтению и при обработке контрольной точки в базе данных. Номер SCN можно рассматривать как счетчик; при каждой фиксации транзакции значение SCN увеличивается на единицу. Осталось прояснить одно: что значит очистить блоки базы данных. Я написал, что некоторые блоки, измененные транзакцией, будут повторно обработаны и очищены в процессе фиксации. Имеется в виду информация о блокировках, хранящаяся в заголовках блоков данных. Далее, в разделе Очистка блоков , этот процесс будет описан подробно. Если коротко, происходит удаление данных транзакции из блока, чтобы следующий посетитель блока был избавлен от необходимости делать это. При этом не генерируются данные в журнал повторного выполнения, что существенно экономит ресурсы.
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0.001
При копировании материалов приветствуются ссылки. |