DeepEdit!

Программирование баз данных на Oracle, техническая документация, литература, статьи и публикации

  • Увеличить размер шрифта
  • Размер шрифта по умолчанию
  • Уменьшить размер шрифта

Время между вызовами базы данных


Ядро Oracle также выводит сведения о фактической продолжительно­сти событий ожидания, которые имеют место между вызовами базы данных. К примерам событий ожиданий, происходящих между вызо­вами базы данных, относятся:
SQL*Net message from client SQL*Net message to client single-task message pipe get
rdbms ipc message pmon timer smon timer
Фрагмент файла трассировки, приведенный в примере 5.4, иллюстри­рует события ожидания, которые имеют место между вызовами базы данных. Рассматриваемое приложение содержит ошибку - слишком часто выполняется разбор, что ограничивает возможность масштаби­рования. Как видите, фрагмент содержит два последовательных вызо­ва разбора (выделенных жирным шрифтом) абсолютно одинакового текста SQL. Строки WAIT (помеченные жирным курсивом) находятся между вызовами разбора - как в смысле их физического расположения в файле трассировки, так и потому, что продолжительности этих собы­тий не учитываются во времени, истекшем с начала второго вызова. Это легко проверить - фактическая длительность, показанная во вто­рой строке PARSE (e=0), слишком мала для того, чтобы вмещать в себя продолжительность события SQL*Net message from client (ela=3).
Т е перь, когда вы все это знаете, вам легче будет представить себе соот­ношение между величинами c, e и ela в рамках всего файла трассиров­ки. Учитывая все вышесказанное, общее время отклика сеанса равно общей продолжительности вызовов базы данных плюс общая продолжительность интервалов времени между такими вызовами. Формаль­но можно представить это отношение так:
Есть, однако, еще одна сложность: наличие рекурсивного SQL приво­дит к двойному учету времени.
Двойной учет рекурсивного SQL
Рекурсивный SQL - это SQL, соответствующий вызову базы данных, значение dep которого больше нуля. Вызов базы данных глубиной dep=n + 1 (n = 0, 1, 2, ...) можно рассматривать как потомка какого-то вызова базы данных со значением dep=n. Сеансы приложений регу­лярно порождают достаточно сложные данные трассировки для пред­ставления всего спектра отношений между командами SQL, высту­пающими друг по отношению к другу в роли предков, потомков и т. д. Любой файл трассировки SQL содержит достаточно информации для того, чтобы можно было точно определить отношения типа «родитель-потомок» между вызовами базы данных. Для того чтобы не учесть ка­кую-нибудь характеристику дважды при вычислении времени откли­ка, надо понимать, как выявить рекурсивные отношения между вызо­вами базы данных.
Отношения типа «родитель-потомок»
Термин рекурсивный характеризует исполнение ядром Oracle вызовов базы данных в контексте других вызовов базы данных. Рекурсивность может быть вызвана: выполнением команд DDL; выполнением блоков PL/SQL, включающих в себя команды DML; вызовами базы данных, к которым приводят к запуску триггеров, а также разнообразными командами DML, требующими доступа к словарю данных. Любой вы­зов базы данных, способный выполнять другой вызов базы данных, может служить причиной возникновения рекурсивного SQL.
Фрагмент файла трассировки, приведенный в примере 5.5, иллюстри­рует использование рекурсивного SQL. В этом фрагменте есть инфор­мация о новом курсоре, помеченном как #2, который сопоставлен сле­дующему тексту SQL:
select text from view$ where rowid=:1
Такого текста не было в исходном тексте исследуемого приложения -он появился в результате разбора запроса из представления DBA_OBJECTS.
Пример5.5. Фрагмент файла трассировки, демонстрирующий рекурсивный SQL. Три операции курсора #2 глубиной dep=1 являются рекурсивными
Правило определения рекурсивного отношения между вызовами базы данных формулируется очень просто:
Вызов базы данных, имеющий глубину dep=n+1, является рекурсивным потомком первого следующего за ним в потоке данных трассировки SQL вызова базы данных, имеющего глубину dep=n.
Пример 5.6 поясняет это правило. Ядро Oracle может выдать данные трассировки для вызова базы данных только по завершении действий (например, ядро не может вычислить фактическую продолжитель­ность вызова, пока он не завершен). Поэтому мы можем воспроизвести последовательность инструкций, приведших к формированию данных трассировки SQL, приведенных в примере 5.5. В частности, в этом примере все вызовы базы данных для запроса к VIEW$ являются рекур­сивными потомками вызова разбора запроса к DBA_OBJECTS. Для того чтобы подчеркнуть рекурсивное отношение «родитель-потомок» меж­ду вызовами базы данных, в тексте примера 5.6 для процедур стека вызовов использованы различные уровни отступа от левого края.
Пример 5.6. Последовательность инструкций ядра Oracle, которая выдает данные трассировки SQL в порядке, приведенном в примере 5.5. Величина отступа выбрана пропорционально глубине вызова
Графическое представление отношения «родитель-потомок» между вы­зовами базы данных дано на рис. 5.2.
Рекурсивные статистики
В версиях Oracle (по крайне мере, вплоть до Oracle9i Release 2) такие статистики вызовов базы данных, как c, e, p, cr и cu, включают в себя ресурсы, потребленные собственно вызовом базы данных и всем его ре­курсивным потомством.

Рекурсивное потомство вызова базы данных состоит из всех ре­курсивных потомков вызова базы данных, включая детей, вну­ков, правнуков и т. д.
На рис. 5.3 представлено такое отношение для вымышленного набора вызовов базы данных. Каждый узел графа (прямоугольник) - это вы­зов базы данных (например, PARSE, EXEC или FETCH). Направленная ли­ния от некоторого узла к узлу означает, что вызов базы данных является рекурсивным родителем (т. е. вызывающим) для вызова базы данных B. Строка cr=n внутри узла - это то значение, которое ядро Ora­cle передаст в файл трассировки для вызова базы данных. Значение crself - это количество чтений в согласованном режиме, выполненных самим вызовом базы данных, без учета значений для дочерних вызовов.
Рис. 5.3. Каждая из величин c, e, p, cr и cu для вызова базы данных включает в себя соответствующие значения для всего рекурсивного генеалогического дерева данного вызова
Ядро выдает в файл трассировки только те значения статистик, кото­рые включают в себя соответствующие значения для потомства, но из них можно извлечь составляющие, исключающие учет работы потом­ства (величины, указанные внутри дочерних вершин). Например, если бы числа внутри узлов на рис. 5.3 отсутствовали, было бы несложно их проставить. Значение каждого узла - это просто значение статистики для данного узла за вычетом суммы значений статистик для прямых потомков данного узла. Значение узла глубины dep=k- это значение cr, указанное для данного вызова базы данных за вычетом суммы зна­чений cr его потомков глубины dep=k + 1. Обобщая, можно сказать,
что количество ресурсов s, потребленных вызовом базы данных глуби­ны dep=k, вычисляется следующим образом:
где si - это значение статистики из набора {c, e, p, cr, cu}, выведенное ядром Oracle в файл трассировки для рекурсивной глубины i.
Описанный метод нетрудно применить к реальным данным трасси­ровки. Обратимся еще раз к вызовам базы данных из примера 5.5. На рис. 5.4 приведено значение фактической продолжительности, включающее статистики для потомства, для каждого вызова базы дан­ных (обозначенное e) и вклад каждого вызова в фактическую продол­жительность без учета статистик потомков (обозначенный eself).
Рис. 5.4. Графическое представление стека рекурсивных вызовов из примера 5.5
В табл. 5.6 собраны все статистики для всех вызовов базы данных из примера 5.5, не учитывающие влияние потомства данных вызовов. На­пример, вклад (без учета потомков) в фактическую продолжительность вызова базы данных PARSE #1 можно вычислить следующим образом:

Ресурсы, потребляемые™
c
e
p
cr
cu
EXEC #2, потомок
0
176
0
0
0
FETCH #2, потомок
0
89
0
2
0
PARSE #1 без учета его рекурсивного потомства
10000
14701
0
0
0
Теперь у нас достаточно информации для завершения формулы учета времени отклика. Избавившись от двойного учета рекурсивного SQL, получим:
То есть общее время отклика по файлу трассировки приблизительно равно сумме значений e для вызовов базы данных рекурсивной глуби­ны 0 плюс сумма значений ela для событий ожидания, которые имеют место между вызовами базы данных. С другой стороны, общее время отклика для файла приблизительно равно сумме значений c вызовов базы данных глубины 0 плюс сумма всех значений ela для файла.

 









jAntivirus