Борчук Леонид Евгеньевич, Череповец
Запрос пользователя к реляционной системе управления базой данных (СУБД) представляет собой выражение на декларативном языке запросов SQL [1-3]. Способ выполнения выбирается системой [4-6]. Процесс выбора называется оптимизацией выполнения запроса. Результатом процесса оптимизации является план выполнения запроса. Целью оптимизации является минимизация времени выполнения запроса. При этом в силу того факта, что о времени в вычислительной системе говорить бессмысленно, оно (время) оценивается затратами ресурсов компонент системы, называемыми стоимостью выполнения запроса.
В статье обсуждается вопрос сравнимости стоимостей выполнения разных запросов. Практическая интерпретация результатов производится для СУБД Oracle 9i.
Cost = (#SRds * sreadtim + #MRds * mreadtim + #CPUCycles / CPUSpeed )/ sreadtim, (1)
где #SRds - оценочное количество одноблочных дисковых чтений;
#MRds - оценочное количество многоблочных дисковых чтений;
#CPUCycles - асимптотически точные оценки количества операций, выполняемых процессором;
#sreadtim - среднее время одного одноблочного дискового чтения;
#mreadtim - среднее время одного многоблочного дискового чтения;
#CPUSpeed - количество операций, выполняемых процессором в единицу времени.
Обсуждение вопросов сбора и интерпретации системной статистики (#sreadtim, #mreadtim, #CPUSpeed) можно найти в [7].
Пример 1. Определение значения системной статистики
/* Тестовая система */ test@ORA9i> select pname, pval1 2 from sys.aux_stats$ 3 where sname= 'SYSSTATS_MAIN'; PNAME PVAL1 ------------------------------ ---------- CPUSPEED 860 MAXTHR 174080 MBRC 8 MREADTIM ,461 SLAVETHR -1 SREADTIM 1,044 6 rows selected.
#sreadtim, #mreadtim, #CPUSpeed) можно сравнивать стоимости выполнения запросов.
С точки зрения корректности сравнения стоимостей разными системами можно считать не только разные физически системы, но и одну и ту же физическую систему в разные моменты времени. Это происходит вследствие того, что базисный вектор в разные моменты времени может иметь разные значения (#sreadtim, #mreadtim, #CPUSpeed) - например, в случае изменения настроек или обновления системной статистической информации.
Пример 2. Стоимость запроса в разных системах
/* Тестовая система */ test@ORA9i> execute dbms_random.seed(0); PL/SQL procedure successfully completed. test@ORA9i> create table t1 2 as select 3 rownum id, 4 trunc(100*dbms_random.normal) val 5 from all_objects, all_objects 6 where rownum < 1000*1000 7 ; Table created. ... Я Сбор статистики test@ORA9i> set autotrace traceonly explain test@ORA9i> select count(*) from t1; Execution Plan ---------------------------------------------------------- 0 SELECT STATEMENT Optimizer=CHOOSE (Cost=784 Card=1) 1 0 SORT (AGGREGATE) 2 1 TABLE ACCESS (FULL) OF 'T1' (Cost=784 Card=999999) /* Рабочая система */ work@ORA9i> select count(*) from t1; Execution Plan ---------------------------------------------------------- 0 SELECT STATEMENT Optimizer=CHOOSE (Cost=1062 Card=1) 1 0 SORT (AGGREGATE) 2 1 TABLE ACCESS (FULL) OF 'T1' (Cost=1062 Card=999999) /* Параметры рабочей системы */ work@ORA9i> set autotrace off; work@ORA9i> select pname, pval1 2 from sys.aux_stats$ 3 where sname= 'SYSSTATS_MAIN'; PNAME PVAL1 ------------------------------ ---------- CPUSPEED 151 MAXTHR 85332992 MBRC 7 MREADTIM 3,188 SLAVETHR -1 SREADTIM 1,84 6 rows selected.
Пример 3. Стоимость и время выполнения разных запросов в одной системе
/* Тестовая система */
test@ORA9i> execute dbms_stats.gather_table_stats('sys','t1',null,100, false,'FOR ALL COLUMNS SIZE 1');
PL/SQL procedure successfully completed.
test@ORA9i> set autotrace on
test@ORA9i> set timing on
test@ORA9i> select count(*) from
2 (select id, count(*) from t1 where val between 100 and 300 group by id);
COUNT(*)
----------
157393
Elapsed: 00:00:03.01
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=3705 Card=1)
1 0 SORT (AGGREGATE)
2 1 VIEW (Cost=3705 Card=219060)
3 2 SORT (GROUP BY) (Cost=3705 Card=219060 Bytes=1752480)
4 3 TABLE ACCESS (FULL) OF 'T1' (Cost=884 Card=219060 Bytes=1752480)
test@ORA9i> select count(*) from
2 (select id, count(*) from t1 where val between -100 and 100 group by id);
COUNT(*)
----------
687375
Elapsed: 00:00:10.05
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=3705 Card=1)
1 0 SORT (AGGREGATE)
2 1 VIEW (Cost=3705 Card=219060)
3 2 SORT (GROUP BY) (Cost=3705 Card=219060 Bytes=1752480)
4 3 TABLE ACCESS (FULL) OF 'T1' (Cost=884 Card=219060 Bytes=1752480)
Обратите внимание, что в примере 3 запросы, имея одинаковую стоимость, включают разные предикаты between 100 and 300 и between -100 and 100, поэтому эти запросы разные. Что и показывает отличие во времени выполнения в 3 раза.
Резюмируя можно сказать, что при сравнении стоимостей выполнения запросов необходимо учитывать особенности физической системы, на которой будет выполняться запрос, а также вероятностный характер оценки.