Събиране на статистики.

На мен лично темата за събиране на статистики, винаги ми е била е интересна. Не за друго, а защото на базата на статистиките се определя и производителността или бързодействието на базата данни. Естествено, не бих казъл, че съм експерт в тази област, но винаги от някъде се тръгва. За това тази тема няма да остане самотна а мисля да бъде с продължения. Като начало е добре да се спрем на основните неща при събиране на статистиките. Първо как да събираме статистики на таблица, индекс, схема и цялата база данни. Всъщност , преди това е добре да изясним защо е нужно да събираме статистиките? Един от ключовите моменти да имаме успех с CBO(Cost Base Optimizer) е внимателно да дефинираме и управляваме статистиките. За да може CBO да направи едно интелигентно решение за най-добрият план за изпълнение на една SQL заявка, той трябва да е информиран за таблиците и индексите, които участват в заявката. Когато CBO знае разпределението, селективноста и главните стойности на колоните, CBO може да генерира почти винаги най-добрият план за изпълнение основан на една добре събрана информация.
      В Oracle 10g съществува един пакет DBMS_STATS, който е предпочитан метод, за това че може да се изпълнява паралелно, да експортира статистиките от един на друг сървър, дълъг период за съхранение на статистиките, опростен синтаксис и мн.др. Именно за това DBMS_STATS е предпочитан за събиране на статистиките. Този пакет има няколко метода с помощтта на които може да събирате статистиките върху конкретни обекти:

  • GATHER_INDEX_STATS - Индекс статистики
  • GATHER_TABLE_STATS - Таблици,колони и индекс статистики
  • GATHER_SCHEMA_STATS - Статистиките за всички обекти в схемата
  • GATHER_DICTIONARY_STATS - Статистиките за всички обекти в "dictionary"-то
  • GATHER_DATABASE_STATS - Статистиките за всички обекти в базата данни
Ето и няколко примера за това как може да се използват съответните методи. С посоченият пример по-долу може да съберете статистиките на една схема.

set timing on
begin
DBMS_STATS.GATHER_SCHEMA_STATS(
ownname => 'SCOTT', 
options => 'GATHER AUTO',
estimate_percent => DBMS_STATS.AUTO_SIMPLE_SIZE,
method_opt => 'for all columns size repeat', 
cascade => TRUE);
end;
/
					

Има няколко стойности, които могат да се дадат на параметъра OPTIONS, които е добре да знаете:

  • GATHER - ще аланизира отново цялата схема.
  • GATHER EMPTY - аланизира само таблиците, за които няма събрани статистики.
  • GATHER STALE - Само таблиците с повече от 10% промени (inserts, updates, deletes) ще бъдат аланизирани.
  • GATHER AUTO - Ще аланизира отново таблиците за които няма събрани статистики, както и за таблици с остарели статистики. Всъщност това е комбинация, все едно използвате GATHER EMPTY и GATHER STALE заедно

... а за събиране на статистиките на една таблица или на индекс изпълнете следното:

set timing on
begin
DBMS_STATS.GATHER_TABLE_STATS(ownname => 'SCOTT',
tabname => 'EMP',
estimate_percent => DBMS_STATS.AUTO_SAMPLE_SIZE,
method_opt => 'for all columns size repeat',
cascade => TRUE,
degree => 5);
end;
/

--- Example to gather index statistics

set timing on
begin
DBMS_STATS.GATHER_INDEX_STATS(
ownname => 'SCOTT',
indname => 'PK_EMP',
estimate_percent => DBMS_STATS.AUTO_SAMPLE_SIZE,
degree => 5);
end;
/

					

Опцията CASCADE
Когато анализирате определена таблица "cascade" опцията може да бъде използвана за да анализирате всички обекти имащи отношение към таблицата, като индексите, и таблиците свързани чрез "foreign-key constraints" .С други думи казано, чрез анализиране на една таблица вие ще извикате и анализирате и други таблици.

Събиране на статистиките по график
Събирането на статистиките по график, чрез пакета DBMS_JOB е най-лесният начин да сме сигурни че те ще са актуални. За това, може да създадете следната задача:

SET SERVEROUTPUT ON
DECLARE
l_job NUMBER;
BEGIN

DBMS_JOB.submit(l_job,
'BEGIN DBMS_STATS.gather_schema_stats(''SCOTT''); END;',
SYSDATE,
'SYSDATE + 1');
COMMIT;
DBMS_OUTPUT.put_line('Job: ' || l_job);
END;
/
					

Кода по-горе ще се изпълнява всеки ден по същото време, когато е стартирана за първи път задачата. Ако искате да премахнете задачата можете да използвате следната команда:

EXEC DBMS_JOB.remove(X);
COMMIT;
					

Където Х е номера на задачата, която искате да премахнете.