Излезе Oracle Database 11g Release 2!

 Без категория  Коментарите са изключени за Излезе Oracle Database 11g Release 2!
сеп. 022009
 

Oracle announces availability of Oracle Database 11g Release 2

Новият release е пълен с благи функцийки, за които с удоволствие ще пиша в следващите дни. Вече всеки може да си го изтегли от OTN

Stay tuned 🙂

 Posted by at 8:08

Пак за преточването на данни

 Без категория  Коментарите са изключени за Пак за преточването на данни
сеп. 012009
 

Като ми следи някой постингите, може да си каже, че само претакам данни насам-натам като зелева чорба. Не е така, рядко се налага, за това пък е хем интересно, хем има достатъчно не-custom, за да мога да го споделям в блога си. А това описание го правя както за споделяне с другите, така и за себе си – след време да не се чудя как го бях направил 🙂

И така, този път ще преточа няколко стотин гигабайта по най-бързия възможен начин: transportable tablespace. Използвам следните уточнения:
– БД-източник е на AIX и е версия 10.2.0.3. БД-приемник е на Linux x64 и е версия 11.1.0.7 (ужасно свежа с пачването, чак до последния CPU), т.е. имаме разлика както във версиите, така и в платформите
– данните в БД-източник са на файлова система, а на БД-приемник ще ги сложа на ASM.
– Имах щастието файловата система на БД-източник да бъде монтирана на сървърите на БД-приемник (read-only), за да мога да си изтакам файловете директно

И понеже има доста tablespaces и ще пренасям данните на порции, гледам да си направя стъпките някак хем прости и малко на брой, хем ефективни. За това си подготвих следните улеснения:
– както вече написах, системните администратори монтираха файловата система с data файловете от системата-източник на сървърите на системата-приемник (read-only!)
– в БД-приемник създадох database link към БД-източник. Напоследък съм много влюбен в използването на Data Pump през databse link (благодаря на Юлиян Дончев, че ми подсказа за това улеснение). По този начин си спестявам генерирането на dump file на едната система и пренасянето му до другата.
– конвертирането на tablespaces става с RMAN. Това е почти единственият начин за прехвърляне на много големи обеми от данни между различни платформи – логическият export/import, бил той по стария начин или с data pump, би отнел ужасно много време. За rman си подготвих скрипт за прехвърляне на данните, за да не набирам всичко всеки път
– прехвърлянето на метаданните, както вече загатнах, извършвам с Data pump. За този етап също си подготвих параметричен файл.

И ето така се достигна до следният сложен механизъм за прехвърляне в 2 стъпки:
1. Конвертиране на файловете от старата платформа към новата, едновременно с прехвърлянето им в ASM. Използвам следният файл:

$ cat ~/rman_convert.cmd


CONVERT DATAFILE '/mnt/oradata/old_db/data/local/big_tbs_01.dbf'
   FROM PLATFORM 'AIX-Based Systems (64-bit)'
   DB_FILE_NAME_CONVERT '/mnt/oradata/old_db/','+DATA/new_db/datafile/';
CONVERT DATAFILE '/mnt/oradata/old_db/data/local/big_tbs_02.dbf'
   FROM PLATFORM 'AIX-Based Systems (64-bit)'
   DB_FILE_NAME_CONVERT '/mnt/oradata/old_db/','+DATA/new_db/datafile/';
CONVERT DATAFILE '/mnt/oradata/old_db/data/local/big_tbs_03.dbf'
   FROM PLATFORM 'AIX-Based Systems (64-bit)'
   DB_FILE_NAME_CONVERT '/mnt/oradata/old_db/','+DATA/new_db/datafile/';
. . .

– За да сработи това трябва съответния tablespace да е read-only на БД-източник през цялото време. Има начини това време да се намали, но за щастие аз мога да си позволя по-дълъг период read-only.
– Както виждате RMAN няма нужда да се закача към БД-източник и не използва контролния и файл, а чете директно посочения datafile.
– Също така тук е интересно, че on-the-fly се случва едно конвертиране от Big endian в Little endian формат на данните.
– Параметърът db_file_name_convert указва как да се промени името на файла (заедно с пътя). По този начин файла се озовава върху ASM
Самото изпълнение се случва така (на новата система):

rman target / cmdfile=~/rman_convert.cmd

2. Прехвърляне на метаданните и „закачане“ на копираните tablespaces в новата БД. Използвам datapump със следния параметричен файл:

$ cat ~/transmore.par
NETWORK_LINK=OLD_DB
TRANSPORT_TABLESPACES=big_tbs_01,big_tbs_02,big_tbs_03, . . .
TRANSPORT_FULL_CHECK=n
TRANSPORT_DATAFILES='+DATA/new_db/datafile/data/local/big_tbs_01.dbf','+DATA/new_db/datafile/data/local/big_tbs_02.dbf','+DATA/new_db/datafile/data/local/big_tbs_03.dbf', . . .
NOLOGFILE=Y
EXCLUDE=STATISTICS

– Важно е пренасяните на един път tablespaces да съдържат всички взаимносвързани обекти – т.е. всички таблици, закачени с foreign keys, всичките им индекси и т.н. Понеже аз знам, че в моя случай съм изпълнил това изискване, инструктирам datapump да не проверява с TRANSPORT_FULL_CHECK=n. Всъщност това си е стойността по подразбиране, но нищо не вреди да я сложа изрично – да се замисля след години като видя същия скрипт
– Параметъра TRANSPORT_DATAFILES указва къде се намират новите файлове. Ако не се зададе това, data pump ще ги търси на същото място, на което са в БД-източник.
– понеже съм си леко мързелив по природа, пък и имам да пренасям десетки tablespaces, си генерирам TRANSPORT_DATAFILES от системата-източник така:

select ''''||replace(file_name, '/mnt/oradata/old_db/', '+DATA/new_db/datafile/')||''',' from dba_data_files; 

Всъщност по аналогичен начин си генерирам и rman скрипта.
Самото извикване на Data pump е

$ impdp system@new_db PARFILE=~/transmore.par

Това е всичко. Само две прости команди… 🙂

 Posted by at 9:02

Есенен семинар на БГПО ’09

 Без категория  Коментарите са изключени за Есенен семинар на БГПО ’09
авг. 102009
 

Лятото е в разгара си, и ако искам то да свърши, то е само за да дойде по-скоро есенния семинар на БГПО. А той е толкова далече…

Преглед на имената от супер-ранно-предварителния списък тук показва стабилно присъствие на хард-лайнери (за какъвто се имам и аз). Но този път едно име направо ме втрещи: Anjo Kolk, Owner, Miracle Benelux, Oracle – Google integration.

Anjo Kolk! Човекът, който измисли YAPP и показа на света как трявба да се гони performance в Oracle! Неговият YAPP метод (Yet Another Performance Profiling Method) е една от основните разлики межу Oracle и другите СУБД.

Anjo е работил 16 години в Oracle, при това доста време в Oracle Server Performance Group. Между другото, в Oracle той е работил и по интеграцията на БД с големи ISV като Amdocs (примерно) и е ходил при много телеком клиенти като NTT Docomo (примерно) 🙂 . След като напуска Oracle, Anjo работи в Precise Software, Veritas Software и Symanctec, а напоследък си е сам шеф в Miracle Benelux, където, предполагам, другарува с Mogens Nørgaard. Покрай другото Anjo (заедно Mogens Nørgaard и други добри хора) е и един от основателите на The Oak Table Network.

 Posted by at 16:59
авг. 102009
 

Задачката е следната:

Близо до офиса има една кръчма (още се спори дали се казва „Дупката“ или „Гнусното“). В нея влизат и излизат много хора. Понеже е доста голяма, има си регистър на влизащите и излизащите. В основната таблица (покрай другото) има и колонки time_in и time_out, които показват даден човек кога е влязъл и кога е излязъл. Ако се случи да дойде втори път (което е съвсем възможно, предвид че въпреки гадната обстановка, в Дупката готвят много вкусно), просто се вкарва нов запис.

Шефа на Дупката обича да знае разни неща. И като човек, обичащ да знае разни неща, иска да знае в кой момент от денонощието има най-много хора в кръчмата, и като цяло как се движи натоварването. Но понеже заведението е наистина голяма, няма начин някой да седи и д брои – трябва да се използват записите в таблицата. Въпреки че Дупката работи денонощно, натоварването е променливо.

В таблицата има около 500-600 хиляди записа на ден. Естествено, използва се partitioning, за да бъде управляем обема.

Ще представя един вариант, както и част от пътя, по който стигнах до него. Естествено, приемам всякакви предложения. Подозирам, че все някой е решавал такава задачка преди мен и аз сега откривам топлата вода.

Първата идея е да се направи pl/sql функция, която да проверява във всеки един момент колко хора е имало. Понеже колонките за дата в таблицата са от тип DATE, ще проверим всяка секунда за дадено денонощие (такава е точността на типа DATE). С един цикъл, за всяка секунда “X”, търсим посещения по следния начин:

SELECT X, COUNT(1)
  FROM client_visits 
 WHERE X BETWEEN time_in AND time_out;

Това се записва в една таблица, от която ваденето на графики става лесно.

Всичко това е хубаво, само че за дадените обеми нещото отнема абсурдно много време на тестовата система: около 30 часа за 24 часов период. И това при наличие на индекс по (time_in, time_out) – иначе няма шанс.

Тук се сещам за един въпрос, който много хора забравят: а трябва ли ни наистина толкова детайлна информация (за всяка секунда)? (виж „Oracle Insights“, глава 3: „Waste Not, Want Not“)

Полезно: Много често се оказва, че с леко облекчаване на бизнес изискванията, задачата става много по-лесно решима.

Така е и в този случай – шефа на Дупката е доволен да знае и как се движи натоварването по минути, не му трябва чак по секунди. Така цикълът (с малко променено условие) ще има 60 пъти по-малко итерации и ще пусне само 1440 заявки, вместо 86400. И (на нашата система) отнема само малко повече от половин час.

Обаче… всеки печен DB expert знае, че в общия случай ако нещо може да стане само с SQL, то е добре да се направи само с SQL. Да стане с една, пък била тя и тежка, заявка – вместо с 1440 по-леки. Естествено, има и изключения, но са много редки.

Първоначално тръгнах по грешен път. Сетих се, че не ми трябва да проверявам всяка секунда (или минута) – стига ми да проверявам за всеки момент, в който влиза някой. Ако в даден момент не влиза никой, там няма да има покачване на натоварването.

select time_in,
       (select count(1)
           from client_visits t2
          where t2.time_in < = t1.time_in
            and t2.time_out >= t1.time_in
            )
  from client_visits t1
 where time_in >= trunc(sysdate - 1) -- гледаме данните за 1 ден
   and time_in < trunc(sysdate)

Това няма да помогне на шефа на дупката да разбере кога има най-малко натоварване, но той така или иначе не се интересува от това - той си оразмерява кръчмето за максималното натоварване, а движението в натоварването му трябва за да си нагоди грубо персонала. Освен това входящите посетители са толкова много (500-600 хиляди посещения на ден), че и без това почти на всяка секунда има поне един влизащ и няма опасност да се пропусне нещо интересно.

Тук, обаче, нещата на вървяха много добре. Честно казано, не изчаках да видя колко време е необходимо, защото всичко над 15 минути ми се струваше твърде много. Тук извадих един друг коз на добрия dataabse expert:

Полезно: Често има неясни зависимости в данните, които помагат да се свърши по-малко работа. Връзки, които са естествени и ясни за нас, но не и за оптимизатора в БД.

Една такава връзка е, че никой не стои в дупката повече от един ден. Или даже и да има такива, те са твърде малко и не променят статистиката. За това направих следната малка оптимизация:

select time_in,
       (select count(1)
           from client_visits t2
          where t2.time_in < = t1.time_in
            and t2.time_out >= t1.time_in
            and t2.time_in > trunc(sysdate) - 2 -- малко оптимизация
            )
  from client_visits t1
 where time_in >= trunc(sysdate - 1) -- гледаме данните за 1 ден
   and time_in < trunc(sysdate)

Това вероятно е подобрило малко нещата, но аз отново нямах търпението да изчакам за да видя колко. Като цяло проблема на този подход е, че се правят твърде много проверки - всъщност, около 500-600 хиляди за един ден (колкото са посещенията).

Следващата идея беше да се изгонят поне повтарящите се проверки:

SELECT time_in,
       (SELECT COUNT(1)
         FROM   client_visits t2
         WHERE  t1.time_in BETWEEN t2.time_in AND t2.time_out
         AND    t2.time_in > trunc(SYSDATE - 2))
FROM   (SELECT DISTINCT time_in -- избягваме повторните проверки
         FROM   client_visits
         WHERE  time_in >= trunc(SYSDATE - 1)
         AND    time_in < trunc(SYSDATE)) t1;

Естествено, и това се оказа твърде бавно. По този начин правим близо 86400 проверки, а вече се разбрахме, че може да направим само 1440. За това се изкуших да направя така:

SELECT time_in,
       (SELECT COUNT(1)
         FROM   client_visits t2
         WHERE  t1.time_in BETWEEN t2.time_in AND t2.time_out
         AND    t2.time_in > trunc(SYSDATE - 2))
FROM   (SELECT DISTINCT trunc(time_in, 'MI') -- намиране само по един запис за всяка минута
         FROM   client_visits
         WHERE  time_in >= trunc(SYSDATE - 1)
         AND    time_in < trunc(SYSDATE)) t1;

Описах този грешен (в случая) път, защото при по-малко данни (примерно ако имахме само 500-600 посещения) би бил полезен. Иначе аз доста бързо се сетих за алтернативата. Само да кажа за последните 2 заявки:

Полезно: Операцията DISTINCT е много тежка при голям обем от данни, защото изисква сортиране на цялото множество.

Освен това с посочените заявки аз преравям 2 пъти данните, които хич не са малко. За това аз се нуждаех от начин да си генерирам всички минути в едно денонощие, без да се ровя в таблицата. Да си измисля данни, с които да направя join. За целта използвах следния трик

Полезно: Генератор за 100 реда с числата от 1 до 100:
select rownum from dual connect by level < = 100

Така стигнах до следния вариант:

SELECT time_in,
       (SELECT COUNT(1)
           FROM client_visits t2
          WHERE t1.time_in BETWEEN t2.time_in AND t2.time_out
            AND t2.time_in > trunc(SYSDATE) - 2) cnt
  FROM (select trunc(SYSDATE - 1) + rownum / 1440 time_in
           from dual
         connect by level < 1440) t1

Това нещо вече се справя за под 7 минути. За съжаление не показва в коя минута има най-много посетители в кръчмата, а в коя нулева секунда от минута. За да сравня целите минути ми трябват и посетителите, които са влезли преди началото на следващата минута. Ако гледам с разредност "секунда", този проблем не стои. Едно друго решение за заобикаляне на този проблем е да правя всички сравнения не с точната стойност на time_in и time_out, а с trunc(time_in, 'MI') и trunc(time_out, 'MI'). Но в този случай губя индекса (което пък се решава с функционален индекс). Но в настоящият вариант мога лесно да променя на колко периода да разделя денонощието - примерно на по 5 минути, или на 10 секунди, за да получа данни с различна точност.

И така, настоящият вариант е следния:

SELECT period_start,
       (SELECT COUNT(1)
           FROM client_visits t2
          WHERE ((t2.time_in < = t1.period_start and t2.time_out > t1.period_start) -- започнали преди периода
                 or -- или
                (t2.time_in > period_start and t2.time_in < period_end)) -- започнали в периода
            AND t2.time_in > SYSDATE - 2) cnt
  FROM (select trunc(SYSDATE - 1) + rownum / 1440 period_start, -- началото на периода
               trunc(SYSDATE - 1) + (rownum + 1) / 1440 period_end -- началото на следващият период
           from dual
         connect by level < 1440) t1

Не ми е трудно да се досетя, че може да има и съвсем различно, по-елегантно и ефективно решение. Ще се радвам ако някой сподели такова 🙂

 Posted by at 8:18

Разходка до Безбог, в снимки

 Без категория  Коментарите са изключени за Разходка до Безбог, в снимки
авг. 032009
 

Миналата седмица разпускахме само на 30-40 километра от Добринище и успях да прикоткам моите жени да се разходим до Безбог. Ех, баирче, баирче…

Пътя до хижа Гоце Делчев изобщо не е такъв, какъвто го помня. Вече е новичък, няма ями, за дупки да не говорим. Път като слънце. За това без проблем стигнахме до долната станция на лифта. Там предстоеше на Ирина да се запознае за първи път с „летящите пейки“. Малко се притеснявах да не се стресира. Нищо подобно – много се изкефи 🙂

И така, ето моите жени до безбожкото езеро:

Винаги се кефя да снимам хижата от тази позиция. Изглежда сякаш е на края на света… 🙂

Подминахме езерото и зпочнахме изкачване на Безбожкия превал. Което нямаше как да направим без да се подкрепим с вафли:

Ето така изглежда превала в най-високата си част:

От другата страна минахме още толкова път пеша, преди да спрем за похапване. Ето ме мен в основата на Полежаните, на фона на Папаз Гьол:

Вляво се вижда основата на Мангър Тепе или Острец, зад него е Момин двор. Между двата е Краледворската лява порта, през която се минава за Тевно езерто. Вдясно от мен е един от най-готините върхове в Пирин: Джангала, известен още като Самодивски връх (прилача малко на огромен трон, но само от тази страна е толкова полегат). В десният край на снимката е Самодивската порта, през която се минава за Валявишките езера по пътя за хижа Демяница.

След като хапнахме, поехме бавно по обратния път заради облаците, които се мотаеха около Момин двор:

На връщане, преди да започнем качването на превала:

Напред и вдясно е връх Безбог, вляво по билото е пътя за Полежан.

Ето един интересен клек, на върха на превала:

Безбожкото езеро и хижата, от върха на превала:

На слизане с летящите пейки цялото небе беше облачно:

 Posted by at 21:30
авг. 032009
 

Миналата седмица ходихме семейно да отпуснем в хотел Делта, край Огняново. Хотелът е много хубав. Намира се малко трудно, дори и с толкова табели. Първата важна отбивка е от Добринище в посока Гоце Делчев, в село Господинци. Там се завива на ляво по един селски път, голяма част от който е в отлично състояние. Само тук-там има дупки, но пък са големи. Минава се през самото село Огняново, и след края на селото има един мост и десен завой, след който започва село Марчево. Точно слeд този десен завой „пътят“ за хотел Делта се намира силно вляво. Дано съм го описал добре и съм бил полезен.

И така… плюсовете на хотела са много. Хотелът всъщност е четири относително кокетни сгради по 3-4 етажа. Стаите са големи. За пръв път ми се случва аз да мога да легна на леглото и на право, и напреки, без да ми висят краката 🙂 . Има прилична баня с вана. Басейна е доволно голям с хладка вода; има и детски, с по-топла вода и нещо като джакузи – кръгло басейнче с диаметър 3-4 метра, пълно с много топла вода и дълбоко колкото да седнеш спокойно на дъното. Край басейна има много паркоместа, полянки за шезлонги и чадъри и т.н. Стаите се чистят редовно и добре. Абе идилия.

Хотел Делта
Четвъртата сграда на хотела

Пo-малкият проблем е, че там всичката вода е минерална. И няма начин да не смърдиш на яйца. Не само в басейна, а и в чешмите, в душа, даже и в тоалетното казанче е минерална. Което може да е хубаво за някои, но на мен ми стана досадно. Като се къпеш, цялата баня става буквално смърдяща. Сапуна не може да се отмива. Водата не е приятна за пиене. Няма и студена вода. Това е нещо, за което не бяхме подготвени, донякъде и по моя вина. Ако някой тръгне да ходи там на почивка, да си вземе туба с трапезна вода а пиене.

Това, заради което едва ли бих отишъл там, е обслужването. На регистратурата трудно намираш обслужване. Сервитьорките в ресторанта ги мързи да гледат. Манджите са пресолени. Водата спира. Изобщо отношението към клиента си е откровено гадно. Явно мениджърът на хотела не е много опитен… Да се чуди човек как хора, които явно нямат опит с хотелиерство, са построили толкова добър (външно) хотел. Може би има нещо общо с европейските пари, за които гордо уведомяваше табелата на входа (по САПАРД – и хотели ли спонсорират?). Между другото там на почивка имаше организирани групи държавни служители, от НОИ.

И така, ако решите все пак да отидете там и се поплацикате в басейнчето, мога да ви дам следните препоръки:

– запасете се с търпение. Персонала просто не знае как да се държи с клиенти. Ако не може да изтърпите администраторката да си довърши разговора с чистачката, преди да ви обърне внимание, не сте за там

– избягвайте ресторанта в сградата на хотела. Там обслужването е леко казано мудно и манджите са пресолени. Най-близкото друго заведение е в двора на хотела, където пекат мръвки на открито барбекю. Там обслужването определено ми хареса, а и имат едни невероятно вкусни печени питки с чеснов сос и масълце. Друго силно препоръчително място е ресторанта на хотел „Рай“, където готвача е много добър, а проциите са огромни.

Шопска салата
Шопска салата в „Рай“. Мащаба се губи, но камарата е внушителна. У дома нямам толкова големи чинии

– Вземете си достатъчно вода за пиене. Водата там просто не може да се пие. Не разчитайте да си купите на място – най-близкият магазин е на 2 километра, а в ресторанта бутилка трапезна вода е 2 лева.

– Добре е да отседнето от понеделник до петък, както бяхме ние. В събота става доста пренаселено – ние си тръгнахме към 8 часа сутринта и вече си личеше фраша.

Иначе мястото е много готино. Ако намерят един кадърен мениджър, който да привлече добър персонал, ще стане приказка.

 Posted by at 20:31
юли 242009
 

Преди 3 дни зададох на учтивите блогочитетели един статистически въпрос. Това, че получих отговори, при това то доста (като за моя блог), ме кара да се чувствам задължен да споделя решението, до което достигнах. Естествено, не мога да претендирам, че е перфектно (или окончателно). Но успях да се вслушам в препоръките и да измисля начин на извличане, при който:
– извличам данните за произволен период (в случая – 90 дни)
– от множеството премахвам всички наблюдения, чиито стойности са под 11% или над 89% (това има още да се доработва, в момента не се държи добре при много еднакви стойности)
– взимам медиана и средно отклонение, с които да правя сравнение на текущата стойност. Не съм намерил начин да взема лесно очакваната стойност (expected value), за това разчитам на медианата
– имам голям контрол върху периодите, за които извършвам наблюденията: примерно мога да премахна уикендите, наблюдавам само за опредени часове и т.н. (това го правя с pl/sql, иначе заявката става твърде брадата)

Както се досещате, смятам с такава заявка да следя определен процес в работата си. В момента тествам решението, за да уточня параметрите. Но за сега се получи нещо такова:

select sum(decode(period, 0, rec_cnt, 0)) Current_records,
       median(case
                 when rec_rank < 0.11 then
                  null
                 when rec_rank > 0.89 then
                  null
                 else
                  rec_cnt
               end) Records_median,
       stddev(case
                 when rec_rank < 0.11 then
                  null
                 when rec_rank > 0.89 then
                  null
                 else
                  rec_cnt
               end) Records_deviation,
  from (select percent_rank() over(order by rec_cnt) rec_rank, rec_cnt, period
           from (select get_sum_period_hrs(input_time) period, sum(people_count) rec_cnt
                    from input_stats
                   where input_time > sysdate - 90
                   group by get_sum_period_hrs(input_time))
          where period >= 0)

Това работи с таблица, в която имам статистика за наблюдаваните стойности, която се попълва на произволен кратък интервал (няколко минути). Ако използвам аналогията от предния пост, в таблицата имам колонка input_time (кога е направен текущия запис) и people_count (колко души са влезли след последния запис). Имам функция get_sum_period_hrs, която ми връща 0 за текущия период, >0 за предишен период на наблюдение и <0 за записи, които са извън желаните от мен периоди на наблюдение.

Не смятам това решение за съвършено или дори за добър пример, но се чувствам длъжен да споделя резултата след като получих толкова помощ от вас 🙂

 Posted by at 9:50

Oracle RAC rolling patchset installation

 Без категория  Коментарите са изключени за Oracle RAC rolling patchset installation
юли 242009
 

Колкото и невероятно да звучи, това нещо е не само възможно, ами и доста лесно. Снощи направихме zero downtime rolling patch на един клъстер от 10.2.0.2 на 10.2.0.4 (само на CRS). Необходимите стъпки са описани в Metalink Note 338706.1 и наистина работят 🙂

Напомням, че който иска да прави rolling upgrade на CRS от 10g на 11g, може да погледне тази статия на Jason Arneil.

 Posted by at 9:17
юли 212009
 

Днес си блъскам главата над сления проблем:

Имам няколко стойности, примерно брой хора, които са влизали между 8:00 и 10:00 часа в сградата, за една седмица назад (може и за повече, ако се налага). Примерно:
Понеделник: 1180
Вторник: 1177
Сряда: 1184
Четвъртък: 1197
Петък:1148
Събота: 1181
Неделя: 1155

За днес имам числото Х. Искам да проверя дали Х е нормално, или се различава значително от другите в множеството.

Най-простият отговор е да намеря средноаритметично на старите стойности и да гледам дали се различавам с повече от зададен процент. Средноаритметичното в случая е 1174.57. Ако приемем, че е допустима разлика от 10%, тогава всяко число между 1068 и 1292 ще се приеме за нормално.

Днес, обаче, има стачка и никой не идва. Така за днес имам стойност 0 и получавам аларма, че нещо не е наред (както се очаква).

Обаче утре за сравнение ще имам следнтие данни:

Вторник: 1177
Сряда: 1184
Четвъртък: 1197
Петък:1148
Събота: 1181
Неделя: 1155
Понеделник: 0

Средноаретметичното е 1006 и границите стават много ралзични: от 914 до 1106. Лесно се вижда, че никоя от „нормалните“ за миналата седмица стойности не влиза и ако дойдат, примерно 1150 души, аз ще получа аларма, че нещо не е наред. И така ще получавам „фалшиви“ грешки цяла седмица, докато нулата не излезе от статистиката.

Въпроса ми е има ли някакъв (за предпочитане, относително прост) метод да се избегне това? Т.е. стойности, които очевидно не принадлежат на множеството, да не се взимат предвид, или поне да влияят по-слабо на стойността, с която сравнявам (средноаритметичната в случая). Сигурен съм, че този проблем е решен и не ми се иска да откривам топлата вода 🙂

 Posted by at 11:54