Добре, де. Сървъра не е хилав. Обаче не е и някакво чудо неземно. Все пак е Dev сървър, на него търкаляме Dev бази.
Проблемът е, че търкаляме 30 Dev бази на един сървър. Вярно, във всеки един момент активно работят само 5-6 от тях (или 1-2). Но не и като дойде време за събиране на статистики. Настъпи ли време за събиране на статистики… жална му майка на сървъра. Всичките 30 бази почват да въртят дисковете – въртят, сумтят… и дисковете клякат. ASM също кляка и понякога дори спира да respond-ва за няколко секунди. В екстремните случаи се случва няколко бази да загинат:
ORA-15064: communication failure with ASM instance
ORA-03113: end-of-file on communication channel
Process ID:
Session ID: 4 Serial number: 1
ASMB (ospid: 8290): terminating the instance due to error 15064
Тук е времето да уточня, че тези 30 бази се създават като копия на една “master” база. Каквото има на нея – такова има на тях. Всеки developer или екип може да си пресъздаде базата като текущо копие на master базата, или, много по-рядко, като копие на базата на другарчето си. Така че ако на master базата пише статистиките да тръгнат в 22:00 часа, рано или късно всички други бази ще започнат да си събират статистики в 22:00. И това, всъщност, е най-най-тежкото нещо, което може да се случи на този сървър.
Ето и решението, което съчиних:
create or replace procedure p_scramble_stats_start as v_start_hour char(1); v_start_min char(2); BEGIN -- disable DBMS_SCHEDULER.DISABLE(name => '"SYS"."MONDAY_WINDOW"', force => TRUE); DBMS_SCHEDULER.DISABLE(name => '"SYS"."TUESDAY_WINDOW"', force => TRUE); DBMS_SCHEDULER.DISABLE(name => '"SYS"."WEDNESDAY_WINDOW"', force => TRUE); DBMS_SCHEDULER.DISABLE(name => '"SYS"."THURSDAY_WINDOW"', force => TRUE); DBMS_SCHEDULER.DISABLE(name => '"SYS"."FRIDAY_WINDOW"', force => TRUE); DBMS_SCHEDULER.DISABLE(name => '"SYS"."SATURDAY_WINDOW"', force => TRUE); DBMS_SCHEDULER.DISABLE(name => '"SYS"."SUNDAY_WINDOW"', force => TRUE); -- "choose" the time select to_char(ora_hash(instance_name, 6)), to_char(ora_hash(instance_name, 59)) into v_start_hour, v_start_min from v$instance; -- set DBMS_SCHEDULER.SET_ATTRIBUTE(name => '"SYS"."MONDAY_WINDOW"', attribute => 'REPEAT_INTERVAL', value => 'freq=daily;byday=MON;byhour='||v_start_hour||';byminute='||v_start_min||';bysecond=0'); DBMS_SCHEDULER.SET_ATTRIBUTE(name => '"SYS"."TUESDAY_WINDOW"', attribute => 'REPEAT_INTERVAL', value => 'freq=daily;byday=TUE;byhour='||v_start_hour||';byminute='||v_start_min||';bysecond=0'); DBMS_SCHEDULER.SET_ATTRIBUTE(name => '"SYS"."WEDNESDAY_WINDOW"', attribute => 'REPEAT_INTERVAL', value => 'freq=daily;byday=WED;byhour='||v_start_hour||';byminute='||v_start_min||';bysecond=0'); DBMS_SCHEDULER.SET_ATTRIBUTE(name => '"SYS"."THURSDAY_WINDOW"', attribute => 'REPEAT_INTERVAL', value => 'freq=daily;byday=THU;byhour='||v_start_hour||';byminute='||v_start_min||';bysecond=0'); DBMS_SCHEDULER.SET_ATTRIBUTE(name => '"SYS"."FRIDAY_WINDOW"', attribute => 'REPEAT_INTERVAL', value => 'freq=daily;byday=FRI;byhour='||v_start_hour||';byminute='||v_start_min||';bysecond=0'); DBMS_SCHEDULER.SET_ATTRIBUTE(name => '"SYS"."SATURDAY_WINDOW"', attribute => 'REPEAT_INTERVAL', value => 'freq=daily;byday=SAT;byhour='||v_start_hour||';byminute='||v_start_min||';bysecond=0'); DBMS_SCHEDULER.SET_ATTRIBUTE(name => '"SYS"."SUNDAY_WINDOW"', attribute => 'REPEAT_INTERVAL', value => 'freq=daily;byday=SUN;byhour='||v_start_hour||';byminute='||v_start_min||';bysecond=0'); -- enable DBMS_SCHEDULER.ENABLE(name => '"SYS"."MONDAY_WINDOW"'); DBMS_SCHEDULER.ENABLE(name => '"SYS"."TUESDAY_WINDOW"'); DBMS_SCHEDULER.ENABLE(name => '"SYS"."WEDNESDAY_WINDOW"'); DBMS_SCHEDULER.ENABLE(name => '"SYS"."THURSDAY_WINDOW"'); DBMS_SCHEDULER.ENABLE(name => '"SYS"."FRIDAY_WINDOW"'); DBMS_SCHEDULER.ENABLE(name => '"SYS"."SATURDAY_WINDOW"'); DBMS_SCHEDULER.ENABLE(name => '"SYS"."SUNDAY_WINDOW"'); END;
Тази процедура си избира произволен час и минута (от 00:00 до 6:59) на база името на инстанса. След това сетва всичките maintenance прозорци (в които се събират статистики) да се отварят в този час. В нашия случай събирането продължава от 5 до 15 минути на база, така че не е проблем.
Направих на всички бази един job, който всяка вечер в 22:00 да изпълнява тази процедура. Така който и да копира от master или от някой друг, ще бъде фикснат най-късно на следващата вечер.
И от тогава не сме имали такива проблеми.