1e3a5f4d

Сколько стоит обновить столбец?


В частности, нас будет интересовать, сколько стоит обновление столбца, если его значение не меняется. Если бы сервер мог выявить, что при обновлении реально ничего не меняется, то дополнительные расходы ресурсов на лишнее обновление были бы минимальны. К сожалению, сервер и не пытается выявлять "лишние" обновления. В конечном итоге, логично предполагать, что при обновлении данные должны меняться. Было бы контрпродуктивно добавлять проверку условия, которое почти всегда будет истинным, просто чтобы немного сэкономить в тем "весьма редких и странных" случаях, когда при обновлении изменения не происходят.

Итак, что же может произойти при обновлении одного столбца в таблице в отдельной транзакции? Понятно, что строку надо заблокировать и данные изменить, а для этого - получить запись списка заинтересованных транзакций (Interested Transaction List - ITL) в блоке. Необходимо захватить слот таблицы транзакций (transaction table slot) в заголовке сегмента отмены (undo segment header) для использования в качестве глобально видимой "ссылки" на транзакцию, а также внести запись отмены в блок отмены, описывающую, как отменить изменения, только что выполненные в блоке данных. Изменения во всех трех блоках необходимо записать в журнал повторного выполнения (первоначально - в буфер журнала), и в этом простом случае потребуется только одна запись повторного выполнения (redo record).

Затем, при фиксации транзакции в слоте таблицы транзакций записывается соответствующее значение номера системного изменения (commit SCN) и он помечается как свободный, а адрес использованного блока отмены тоже можно записать в пул свободных блоков в блоке заголовка сегмента отмены. Эти изменения в блоке заголовка сегмента отмены записываются в журнал повторного выполнения (в буфер), а для сброса буфера журнала на диск вызывается процесс записи журнала (log writer process - lgwr), после чего пользовательский процесс уведомляют, что транзакция успешно зафиксирована. (Oracle может, а в этом случае, скорее всего, и будет также очищать измененный блок данных, но не будет записывать выполненные при очистке изменения в журнал повторного выполнения).


Предположим, пользователь изменил на экране всего одно поле - представленное выше описание дает понять, какой объем работы придется выполнить серверу, чтобы реализовать это изменение. Но что, если генератор форм обновил всю строку - какие дополнительные расходы ресурсов при этом возникают?

Затраты на получение записи ITL, блокирование и обновление строки, вероятно, не сильно изменятся, а затраты на получение блока заголовка сегмента отмены вообще не изменятся.

Но вот объем данных в записи отмены, вероятно, возрастет существенно - вместо дополнительных примерно 100 байт плюс старая версия одного столбца мы получим дополнительные байты плюс старая версия всех столбцов. Вероятно, это не так уж важно, - в конечном итоге, сервер Oracle пишет блоки, а не записи, - но если записи отмены в результате выросли по размеру в четыре раза, придется записывать в четыре раза больше блоков отмены.

Аналогично, существенно изменится и запись повторного выполнения. В идеале, запись повторного выполнения будет для этого изменения длиной около 200 байтов (плюс еще 200, связанных с с блоком заголовка сегмента и вектором аудита транзакции). Эта запись, вероятно, будет дополнена до 512 байтов (типичный минимальный размер блока ОС) всяким мусором при фиксации транзакции. Но основная запись повторного выполнения состоит, по сути, из двух векторов изменений - вектора для блока таблицы и вектора для записи отмены, - и оба они увеличатся в размере, потому что запись отмены будет включать старую версию всех столбцов, а запись повторного выполнения для таблицы - новую версию всех столбцов. Поэтому объем генерируемых данных повторного выполнения увеличивается в два-четыре раза, а во многих интенсивно загруженных системах скорость сброса данных повторного выполнения на диск часто является критической проблемой производительности.


Содержание раздела