В рамках решения задачи повышения скорости выполнения запросов с подзапросами поиска данных, удовлетворяющих шаблону, необходимо сравнить скорость выполнения запросов с и без применения предложенного способа оптимизации [1]. Для этого использовался метод тестирования производительности, описанный в данной статье. Предлагаемый метод будет интересен многим администраторам баз данных (АБД).
Каждый АБД часто сталкивается с необходимостью проверки, как изменение в базе данных (БД) или среде ее функционирования скажется на ее производительности. Например, изменение критических параметров оптимизатора запросов, смена версии СУБД, замена сервера и т.д. Наиболее простым решением является тестирование задач вручную или использование готовых тестов, подобных TPC [2]. Первый метод не дает достоверных результатов, второй - выполняет набор запросов в соответствии с заданными шаблонами, которые могут быть очень далеки от действительно выполняемых в БД. Одним из решений данной проблемы является использование средства Oracle Application Testing [3], которое может применяться в БД, работающих под управлением СУБД одноименной компании. Данный продукт позволяет сделать запись действительной рабочей нагрузки БД и воспроизвести ее в тестовой среде. Но заявленная проблема не решается для СУБД, несовместимых с данным ПО. Ниже описан метод, позволяющий имитировать работу БД на основании ранее выполненных в ней запросов.
Выше было отмечено, что большинство тестов не могут моделировать задачи, решаемые в конкретной БД, нам же необходимо протестировать класс запросов из производственной БД. Для выполнения поставленной задачи, а именно, разработки методики тестирования производительности БД на основе воспроизведения ее индивидуальной рабочей нагрузки, необходимо разработать способ получения запросов, ранее выполненных в анализируемой БД. Выполняя эти запросы в БД, будем имитировать работу пользователей, тем самым повысив достоверность тестов. При этом необходимо регистрировать время их выполнения и параметры. Затем для получения результатов эксперимента необходимо выявить и отбросить измерения с высоким уровнем погрешности и на основании оставшихся сделать выводы о работе БД. Рассмотрим каждую из указанных задач.
После выполнения сам запрос и связанные с ним структуры (например, план выполнения) некоторое время находятся в памяти, выделенной СУБД. Следовательно, обратившись к данной области памяти, можно получить требуемую нам информацию, а именно – текст запроса. Например, в СУБД Oracle 10.2 есть системное динамическое представление V$SQLTEXT, содержащее текст операторов SQL, принадлежащих разделяемым курсорам в системной глобальной области (SGA) [4]. Обратившись к нему, можно получить требуемую информацию, т.е. выполняемые в БД запросы. В DB2 для этих же целей можно воспользоваться sysibmadm.snapdyn_sql, в MSSQL – sysprocesses и функцией fn_get_sql.
Рассмотрим более подробно процесс получения выполненных запросов в СУБД Oracle. Представление V$SQLTEXT включает следующие атрибуты: ADDRESS, HASH_VALUE – используемые для уникальной идентификации курсора в кэше; PIECE – порядковый номер фрагмента запроса; SQL_TEXT – фрагмент запроса. По той причине, что размер атрибута SQL_TEXT ограничен 64 байтами, не все выполненные запросы помещаются в указанный формат. В этом случае запрос разбивается на несколько частей (PIECE), и каждой из них присваивается свой порядковый номер – атрибут PIECE. При помощи адреса, хеш-идентификатора и идентификатора части запроса, выполняется слияние «кусков». Ниже приведен код программы на языке PL/SQL, осуществляющий данные действия. В переменной f_sql будут содержаться искомые запросы.
DECLARE f_sql VARCHAR (32767); BEGINFOR h IN (SELECT hash_value, address, MAX (s.piece) FROM v$sqltext s WHERE s.piece < 511 GROUPBY hash_value, address ORDERBY 1) LOOP f_sql := NULL; FOR p IN (SELECT sql_text, piece FROM v$sqltext WHERE hash_value = h.hash_value AND address = h.address AND piece < 511 ORDERBY piece) LOOP f_sql := f_sql || p.sql_text; END LOOP; DBMS_OUTPUT.put_line (f_sql); END LOOP; END; |
Введенное ограничение на количество частей запросов piece<511 вызвано тем, что максимальная длина строки в СУБД – 32767 символов, и при большем количестве они не помещаются в переменную f_sql. Использование других средств программирования снимает данное ограничение. Так как запросы вытесняют друг друга из памяти по мере выполнения, необходимо осуществлять обращение к представлению с некоторой периодичностью. Создав подобное задание и сохраняя результаты его работы, можно получить выполненные пользователем запросы за требуемый период. Если в БД запущен периодический сбор статистики средствами СУБД, такими как StatsPask или AWR [5], то для получения требуемых данных можно обратиться к представлению схемы SYS STATS$SQLTEXT (StatsPask) или DBA_HIST_SQLTEXT (AWR). При работе с последним вся требуемая информация хранится в поле SQL_TEXT типа CLOB. Это упрощает получение данных, т.к. нет необходимости выполнять слияние частей запроса.
Получив выполненные запросы за требуемый период, нужно отфильтровать необходимые. Для этого можно воспользоваться регулярными выражениями. Также отметим, что часть запросов не будут содержать переменные, указанные пользователем в явном виде. Вместо них могут присутствовать переменные связывания (:SYS_0). Следовательно, дальнейшее их выполнение в БД для проведения тестирования бессмысленно. В этом случае вместо связанных переменных можно указывать значения из отношения, по которому выполняется выборка в данном запросе, или отбросить подобные запросы. Можно также изменять значения переменных из запросов для увеличения количества тестовых наборов.
Перейдем к следующему этапу, а именно – этапу их выполнения и сбору статистики работы.
Получив множество запросов, которые были ранее выполнены в БД, необходимо разделить их на несколько групп и одновременно выполнить в БД, тем самым моделируя многопользовательскую среду. Каждая группа запускается по несколько раз. Для анализа процесса выполнения предлагается использовать трассировку сессии, подобная функция присутствует практически во всех СУБД. Аналогично вышесказанному рассмотрим запуск и разбор результатов трассировки в СУБД Oracle [5]. Для этого перед выполнением запросов из групп в БД необходимо выполнить команду:
ALTER SESSION SET EVENTS '10046 trace name context forever, level 1'; |
Уровень трассировки, задаваемый параметром level, можно изменять. Для решения поставленной задачи хватит первого уровня, в случае необходимости получения статистик по событиям ожидания можно воспользоваться восьмым уровнем. В результате выполнения данной команды на сервере БД формируется файл отчета. В нем хранится информация о ходе работы сессии, обо всех выполненных операторах (на различных стадиях выполнения), событиях ожидания, возникших в процессе работы сессии, и т.д. Данный файл плохо структурирован, но из него при помощи утилиты Tkprof, поставляемой с сервером СУБД, можно получить обработанный трассировочный файл. Это упростит автоматическую обработку результатов эксперимента. В анализе каждого из запросов, выполненных в БД и представленных в трассировочном файле, нет смысла из-за возможности получения большого количества информации, обработать которую будет очень сложно. В полученном файле нас будет интересовать часть, хранимая под заголовком: «OVERALL TOTALS FOR ALL NON-RECURSIVE STATEMENTS».
OVERALL TOTALS FOR ALL NON-RECURSIVE STATEMENTS
call |
count |
cpu |
elapsed |
disk |
query |
current |
rows |
Parse |
1048 |
0.10 |
0.13 |
0 |
0 |
0 |
0 |
Execute |
1048 |
0.31 |
0.27 |
0 |
0 |
0 |
0 |
Fetch |
1047 |
185.93 |
190.46 |
8848 |
8011691 |
0 |
3736 |
total |
3143 |
186.35 |
190.87 |
8848 |
8011691 |
0 |
3736 |
Здесь содержится информация о суммарном времени выполнения всех запросов, выполненных дисковых операциях, количестве считанных строк и т.д. Необходимо отметить, что в процессе трассировки имя трассировочного файла по умолчанию генерируется в зависимости от процесса ОС, в рамках которого происходит работа. Это усложняет идентификацию групп запросов для дальнейшего сравнения. С целью устранения данной проблемы для упорядочивания получаемых файлов и выполняемых наборов запросов при помощи команды: alter session set tracefile_identifier=name будем присваивать результирующему файлу имя, определяемое параметром «name». Это позволить провести обработку и анализ результатов эксперимента. Параметр name предлагается формировать из двух частей: идентификатора группы запроса и номера эксперимента с данной группой, например, name=a_2. Это позволит выделять при обработке результатов различные группы и эксперименты.
Разработав средства, позволяющие автоматически получать из исходных трассировочных файлов обработанные утилитой Tkprof, а также выполняющие чтение информации из них, выберем требуемые данные и сохраним. Методы запуска и обработка результатов трассировки в других СУБД будут подобными. Далее необходимо обработать полученные результаты экспериментов для фильтрации измерений с грубой погрешностью, для этого предлагается использовать метод, описанный в следующем разделе.
По причине того, что измерение физической величины не может быть выполнено абсолютно точно, любое измерение дает приближенный результат, иначе говоря, содержит погрешность измерения [6]. С целью повышения достоверности полученных в результате эксперимента значений необходимо проводить по несколько опытов над каждой группой запросов. При этом надо быть уверенным в воспроизводимости эксперимента, т.е. в том, что все полученные в опытах значения являются результатом случайного рассеянья, а не результатом доминирующего действия какого-либо неконтролируемого и неуправляемого воздействия, которое может возникнуть при проведении опыта. Для исключения грубых погрешностей применяют аппарат проверки статистических гипотез.
При обработке уже имеющихся результатов наблюдений произвольно отбрасывать отдельные результаты не следует, так как это может привести к фиктивному повышению точности результата измерений [7]. Группа измерений (выборка) может содержать несколько грубых погрешностей, и их исключение производят последовательно, по одному. Существует множество методов отсеивания ошибочных результатов измерений такие как: критерий Ирвина; критерий вариационного размаха; критерий Диксона; критерии трех сигм, Райта; критерий Смирнова; критерий Шовене; критерий Романовского и др. [8]. По критерию Романовского, конкурирующая гипотеза о наличии грубых погрешностей в подозрительных результатах подтверждается, если выполняется неравенство: |x-X|>=t*S, где t – квантиль распределения Стьюдента при заданной доверительной вероятности с числом степеней свободы k=n-l (l - число подозрительных результатов наблюдений); x - подозрительный результат измерения; X - координата центра распределения; S – среднеквадратичное отклонение. Точечные оценки распределения X и S результатов наблюдений вычисляются без учета l подозрительных результатов наблюдений.
Выполним обработку результатов эксперимента следующим образом:
В качестве результатов наблюдений предлагается использовать время, затрачиваемое на выполнение запросов (строка total, столбец elapsed из обработанного трассировочного файла), и время, затрачиваемое ЦП при выполнении запросов (строка total, столбец cpu из обработанного трассировочного файла).
Координата центра распределения X определяется положением случайной величины на числовой оси и может быть найдена несколькими способами. Наиболее фундаментальным [9, 10] является определение центра по принципу симметрии, т. е. такой точки на оси, слева и справа от которой вероятности появления различных значений случайной величины одинаковы и равны 0,5. В условиях, когда отсутствуют сведения о законе и виде распределения за оценку центра X рекомендуется принимать медиану вариационного ряда оценок: среднее арифметическое; медиана наблюдений; среднее арифметическое 90%-ной выборки; срединный размах вариационного ряда; центр размаха.
Напомним, что каждый набор запросов был идентифицирован, и каждый эксперимент пронумерован. Следовательно, мы можем выбрать данные, соответствующие каждой группе запросов. Для каждой группы нужно отбросить результаты экспериментов с грубой погрешностью и вычислить X и S. Получив X для каждого эксперимента, можно сравнить результаты до изменения БД или ее окружения и после, на основании чего сделать выводы о целесообразности использования предлагаемых методов оптимизации производительности БД.
В рамках данной работы была предложена методология проведения экспериментов в БД, позволяющая сравнить производительность выполнения запросов индивидуальных для данной БД до и после выполнения требуемых изменений. Для решения этой задачи предложены методы получения запросов, ранее выполненных в БД, регистрации времени и статистики их выполнения, обработки результатов измерений. Предложенный метод использован для апробации способов повышения производительности запросов с подзапросами поиска данных, удовлетворяющих шаблону, где зарекомендовал себя с лучшей стороны. Указанный метод будет интересен многим АБД и разработчикам, которым требуется провести сравнения работы БД в различных условиях. При этом отмечается, что данная методика не является универсальной и, что не все требуемые вопросы были рассмотрены. В качестве направлений дальнейших исследований можно выделить исследования, позволяющие более точно обеспечить моделирование многопользовательской работы БД.