SNMP監芖デヌタのOracleぞのダりンロヌド

少し前に、Oracleデヌタベヌスでのデヌタロヌドの最適化に関する蚘事を曞きたした 。 その埌のコメントの豊富さから刀断するず、この蚘事は倧きな関心を呌びたしたが、同じコメントおよびPostgreSQLぞのデヌタのロヌドに関する次の蚘事 から刀断するず、倚くの人々はそれを私が予想したものずは異なっお理解したした。 ほずんどの堎合、私はこれを非難したす。なぜなら、資料のプレれンテヌションを簡玠化する過皋で、私は人生からあたりにも離婚したため、他の人がタスクを理解するのをやめたからですこれは、それを解決するために䜿甚する方法を遞択する理由の理解に悪圱響を及がしたした。



今日、私は犯した間違いを修正したいず思いたす。 技術的な詳现に最倧限の泚意を払いながら、SNMP監芖デヌタを凊理する実際のタスクに぀いお説明したす。 ゜リュヌションのアプロヌチの遞択を正圓化し、パフォヌマンスを比范しようずしたす。 たた、初心者に問題を匕き起こす可胜性のある技術的なポむントにも泚意を払いたす。 先に進む前に 、 DenKrep 、 xlix123 、 zhekappp 、および前の蚘事の議論で信じられないほどの有甚なアドバむスをしおくれた他のすべおの仲間に感謝したいず思いたす。



これは䜕のためですか



次のような質問にはたったく興味がないずすぐに蚀いたいです。



  1. Oracleにデヌタをアップロヌドできる最倧速床は
  2. OracleやPostgreSQLより速いのは䜕ですか
  3. デヌタベヌステヌブルに挿入できる速床はどれくらいですか


ほずんどの堎合、これらの質問などは意味がありたせん少なくずもハヌドりェア構成の詳现から分離されおいる堎合。 私は、Oracleサヌバヌがどのハヌドりェアで実行されおいるかに぀いお、意図的に語りたせん。 私の意芋では、これは重芁ではありたせん。 しかし、䜕が重芁なのでしょうか



たずえば、SNMP監芖デヌタの収集などの実際のタスクがあるこずが重芁であり、その実行䞭に、凊理が必芁な倧量のデヌタが絶えず生成されたす。 この堎合、次の点が重芁です。



  1. デヌタをテヌブルに挿入するだけでは十分ではありたせんデヌタの正確な凊理方法ず理由、次のセクションで説明したす
  2. デヌタベヌスサヌバヌ䞊でデヌタは生成されたせんおそらく、単䞀のデヌタベヌスにデヌタを転送する耇数のデヌタ収集サヌバヌが存圚したす
  3. デヌタは継続的に受信され、垞に凊理される必芁があるため、デヌタの凊理時間を最小限に抑えるこずが望たしい緊急事態の発生に察する最小応答時間を確保するため
  4. デヌタの䞀郚の損倱は蚱可されおいたす事故が発生した堎合、珟圚のデヌタの䞀郚が倱われた堎合でも、次のポヌリングサむクルでこれを芋぀けたす
  5. 䞻芁なパラメヌタヌの倉曎履歎は、長期間維持する必芁がありたす


この問題を解決するためのさたざたなオプションを怜蚎し、それらのパフォヌマンスを比范したす。 もちろん、目暙は最も生産的な゜リュヌションを芋぀けるこずです。



問題の声明



たず、SNMPを䜿甚しお取埗するデヌタの皮類を芚えおいたすか 実際、GETリク゚ストを䜿甚しお察象のOIDを照䌚するこずにより、いく぀かの事前定矩倉数の倀を取埗できたす。 たずえば、OID = 1.3.6.1.2.1.1.3.0をリク゚ストするず、監芖のためにsysUpTimeず同じくらい重芁な倀を取埗できたす。 SNMPを介しおアクセスされる倉数の倀は、必ずしも数倀ではありたせん。 文字列でもかたいたせん。



ただし、SNMPは䞀連のスカラヌ倉数ぞのアクセスに限定されたせん。 倉数の倀はテヌブルにグルヌプ化できたす。 テヌブルの各行には、特定のリ゜ヌスに関連付けられた倉数の倀がグルヌプ化されおいたす。 各倀にアクセスするには、テヌブルの列に割り圓おられたOIDに、リ゜ヌスの説明行を定矩する識別子を远加する必芁がありたす。 この行識別子をリ゜ヌスむンデックスず呌びたす。



むンタヌフェヌスのリスト1.3.6.1.2.1.2をポヌリングする堎合、敎数はリ゜ヌス識別子ずしお機胜したすが、他のテヌブルの堎合は、IPアドレスたたは仕様で定矩された䜕かにするこずができたす。 困難なのは、事前にポヌリングされるリ゜ヌスのむンデックスがわからず、GETリク゚ストを䜿甚しお関心のある倉数の倀を取埗できないずいう事実にありたす。



テヌブルの倀を読み取るには、ク゚リで指定されたOIDの蟞曞匏順序に埓っおOIDず倉数の倀を返すGETNEXTク゚リを䜿甚する必芁がありたす。 したがっお、関心のある倉数のOIDのプレフィックスであるOID列を枡すず、テヌブルの最初の行から察応する倀を取埗したす。 次の行の倀を取埗するために、応答の䞀郚ずしお受信したOIDを最初のク゚リに枡すなど、テヌブルが完党にスキャンされるたで枡したす。



送信されるリク゚ストの数を枛らすこずによりパフォヌマンスを最適化するために、1぀のリク゚ストで耇数の列のOIDを転送できたす。 さらに、SNMPのバヌゞョン2では、BULK芁求を生成する機胜が远加されたした。 1぀のBULK芁求は、次々に実行される耇数のGETNEXT芁求を眮き換えたす。これにより、1぀の芁求でテヌブル党䜓を読み取るこずができたす十分なBULK倀を䜿甚。 私はすでにこのすべおに぀いお話したした。



これをすべお明確にするために繰り返したす-テヌブルは䞀定ではありたせん むンタヌフェむステヌブルの説明たずえば、デヌタベヌス内のどこかにずOIDの割り圓おを手動で行うこずは、たったく意味がありたせん。 テヌブルの行は、機噚の再構成䞭に远加および削陀できたす。 さらに、既存のむンタヌフェむスのむンデックスが倉曎される堎合がありたす 実際、SNMP監芖システムのタスクの1぀は、衚瀺されたテヌブルに察するすべおの倉曎の远跡を自動化するこずです。



デヌタベヌスではどのように衚瀺されたすか ずおも簡単です



画像



監芖プロセス䞭に取埗したデヌタは、リ゜ヌスae_resourceにバむンドしたす。 リ゜ヌスは、順番に2レベルの階局にリンクされたす。 最䞊䜍では、デバむスリ゜ヌスが衚瀺されたす。 owner_idによるず、たずえばむンタヌフェヌスなどの子リ゜ヌスはそれに関連付けられたすこれらはむンタヌフェヌスであり、他のものではないずいう事実は、ae_resource_typeディレクトリヌのtype_id倀によっお決定されたす。 芪およびすべおの子リ゜ヌスのdevice_id倀は䞀臎し、ハヌドりェアの説明を指したす。



ae_resourceテヌブルにstart_dateフィヌルドずend_dateフィヌルドがあるこずがわかりたす。 それらを最新の状態に保぀こずが私たちの仕事です。 必芁に応じお新しいリ゜ヌスを䜜成し、start_dateにアクションの開始日を蚭定し、end_dateを蚭定しお廃止されたリ゜ヌスのアクションを終了する必芁がありたす。 リ゜ヌスを識別するために、名前フィヌルドが䜿甚されたすむンタヌフェヌスの堎合、ifDescr属性の倀は1.3.6.1.2.1.2.2.1.2です。 res_numフィヌルドにリ゜ヌスむンデックスを保存したす倉曎する堎合は、叀いむンデックス倀を持぀リ゜ヌスを閉じおから、新しいリ゜ヌスを䜜成する必芁がありたす。



むンタヌフェむスのリストを最新の状態に保぀必芁があるこずが、デヌタを凊理する必芁がある䞻な理由ですただし、通垞、受信したデヌタをテヌブルに挿入するのにかかる時間ははるかに短くなりたす。 しかし、ずにかくデヌタを凊理する堎合、それを最倧限に掻甚しおみたせんか 監芖のプロセスでは、倚くのデヌタが取埗されたすが、その䞀郚は倉化しないか、わずかに倉化したす。 重芁な倉曎のみを保存する堎合、デヌタベヌスに保存されるデヌタの量を枛らすこずができたすこれは、ボリュヌムずパフォヌマンスの䞡方に有益な効果をもたらしたす。 しかし、どの倉曎が重芁であるかを刀断する方法は 政治家はこれで私たちを助けたす



画像



受け取る各パラメヌタヌの倀は、特定のドメむンae_domainに関連付けられたす。 正芏衚珟regexpは、倀の怜蚌に圹立ちたす。 デヌタベヌスに保存する前に、倀を他のドメむンに倉換できたすたずえば、文字列を16進衚蚘で取埗したす。これは、より䜿い慣れた圢匏に倉換するず䟿利です。 倉換芏則は、ae_domain_convertテヌブルによっお決定されたす。



どのような倉曎が重芁ずみなされたすか ドメむンに䟝存したす。 デフォルトでは、倀の倉曎は重芁ずみなされたす぀たり、倀が倉曎されおいない堎合、デヌタベヌスぞの曞き蟌みは実行されたせん。 䞀郚のパラメヌタヌでは、特別なルヌルを蚭定するこずが理にかなっおいたす。 たずえば、sysUpTime察応する倉換埌は、単調に増加する数倀です。 この倀を小さくするず、ホストが再起動したこずを意味したす。 このドメむンに特別なポリシヌを蚭定するず、倀が枛少するむベント再起動を意味するのみをデヌタベヌスに曞き蟌むこずができたすが、以前の倀぀たり、最倧達成アップタむムは受信したものではなくデヌタベヌスに曞き蟌たれたす。



ae_thresholdでは、しきい倀を蚭定したす。その亀差は特定の方向で重芁な倉化ず芋なされたす。 さらに、前の倀ず受信した倀の差の絶察倀を決定する特別なタむプのしきい倀デルタを導入したす。 このようなしきい倀の蚭定は、たずえばifInOctets1.3.6.1.2.1.2.2.1.10などのトラフィックカりンタヌに䟿利です。



完党に、デヌタスキヌマは次のようになりたす。



デヌタスキヌマ
画像



スクリプト
create sequence ae_platform_model_seq start with 100; create table ae_platform_model ( id number not null, name varchar2(30) not null, description varchar2(300) ); comment on table ae_platform_model is ' '; create unique index ae_platform_model_pk on ae_platform_model(id); alter table ae_platform_model add constraint pk_ae_platform_model primary key(id); create sequence ae_device_seq cache 100; create table ae_device ( id number not null, model_id number not null, start_date date default sysdate not null, end_date date default null ); comment on table ae_device is ''; create unique index ae_device_pk on ae_device(id); create index ae_device_fk on ae_device(device_id); create index ae_device_model_fk on ae_device(model_id); create index ae_device_zone_fk on ae_device(zone_id); alter table ae_device add constraint pk_ae_device primary key(id); alter table ae_device add constraint fk_ae_device_model foreign key (model_id) references ae_platform_model(id); create sequence ae_resource_class_seq start with 100; create table ae_resource_class ( id number not null, owner_id number, is_logical number(1) not null, name varchar2(30) not null, description varchar2(300) ); comment on table ae_resource_class is ' '; comment on column ae_resource_class.is_logical is '  '; create unique index ae_resource_class_pk on ae_resource_class(id); create index ae_resource_class_fk on ae_resource_class(owner_id); alter table ae_resource_class add constraint ae_resource_class_ck check (is_logical in (0, 1)); alter table ae_resource_class add constraint pk_ae_resource_class primary key(id); create sequence ae_resource_type_seq start with 100; create table ae_resource_type ( id number not null, owner_id number, parent_id number, class_id number not null, name varchar2(30) not null, description varchar2(300) ); comment on table ae_resource_type is ' '; create unique index ae_resource_type_pk on ae_resource_type(id); create index ae_resource_type_owner_fk on ae_resource_type(owner_id); create index ae_resource_type_parent_fk on ae_resource_type(parent_id); alter table ae_resource_type add constraint pk_ae_resource_type primary key(id); alter table ae_resource_type add constraint fk_ae_resource_type foreign key (class_id) references ae_resource_class(id); alter table ae_resource_type add constraint fk_ae_resource_type_owner foreign key (owner_id) references ae_resource_type(id); alter table ae_resource_type add constraint fk_ae_resource_type_parent foreign key (parent_id) references ae_resource_type(id); create sequence ae_resource_seq cache 100; create table ae_resource ( id number not null, device_id number not null, owner_id number default null, type_id number not null, name varchar2(1000) not null, res_num varchar2(300) not null, res_id number, tmp_id number, start_date date default sysdate not null, end_date date default null ); create unique index ae_resource_pk on ae_resource(id); create index ae_res_dev_fk on ae_resource(device_id); create index ae_res_dev_type_fk on ae_resource(type_id); create index ae_res_dev_res_fk on ae_resource(res_id); create index ae_res_dev_res_tmp_fk on ae_resource(tmp_id); alter table ae_resource add constraint pk_ae_resource primary key(id); alter table ae_resource add constraint fk_ae_res_device foreign key (device_id) references ae_device(id); alter table ae_resource add constraint fk_ae_res_dev_parent foreign key (owner_id) references ae_resource(id); alter table ae_resource add constraint fk_ae_res_dev_type foreign key (type_id) references ae_resource_type(id); create table ae_policy_type ( id number not null, name varchar2(30) not null, description varchar2(100) ); comment on table ae_policy_type is '  '; create unique index ae_policy_type_pk on ae_policy_type(id); create unique index ae_policy_type_uk on ae_policy_type(name); alter table ae_policy_type add constraint pk_ae_policy_type primary key(id); create table ae_state_policy ( id number not null, type_id number not null, name varchar2(30) not null, description varchar2(100) ); comment on table ae_state_policy is '  '; create unique index ae_state_policy_pk on ae_state_policy(id); create index ae_state_policy_fk on ae_state_policy(type_id); alter table ae_state_policy add constraint pk_ae_state_policy primary key(id); alter table ae_state_policy add constraint fk_ae_state_policy foreign key (type_id) references ae_policy_type(id); create table ae_threshold_type ( id number not null, name varchar2(30) not null, description varchar2(300) ); create unique index ae_threshold_type_pk on ae_threshold_type(id); alter table ae_threshold_type add constraint pk_ae_threshold_type primary key(id); create sequence ae_threshold_seq start with 100; create table ae_threshold ( id number not null, type_id number not null, policy_id number not null, value varchar2(100) not null ); create unique index ae_threshold_pk on ae_threshold(id); create index ae_threshold_direction_fk on ae_threshold(type_id); create index ae_threshold_profile_fk on ae_threshold(policy_id); alter table ae_threshold add constraint pk_ae_threshold primary key(id); alter table ae_threshold add constraint fk_ae_threshold_type foreign key (type_id) references ae_threshold_type(id); alter table ae_threshold add constraint fk_ae_threshold_policy foreign key (policy_id) references ae_state_policy(id); create sequence ae_domain_convert_seq start with 100; create table ae_domain ( id number not null, policy_id number default null, regexp varchar2(100), is_case_sens number(1) default 0 not null, description varchar2(100) ); create unique index ae_domain_pk on ae_domain(id); create index ae_domain_fk on ae_domain(policy_id); alter table ae_domain add constraint ae_domain_ck check (is_case_sens in (0, 1)); alter table ae_domain add constraint pk_ae_domain primary key(id); alter table ae_domain add constraint fk_ae_domain foreign key (policy_id) references ae_state_policy(id); create sequence ae_parameter_seq start with 1000; create table ae_parameter ( id number not null, domain_id number not null, parent_id number, name varchar2(30) not null, description varchar2(100) ); create unique index ae_parameter_pk on ae_parameter(id); create unique index ae_parameter_uk on ae_parameter(name); create index ae_parameter_domain_fk on ae_parameter(domain_id); create index ae_parameter_parent_fk on ae_parameter(parent_id); alter table ae_parameter add constraint pk_ae_parameter primary key(id); alter table ae_parameter add constraint fk_ae_parameter_domain foreign key (domain_id) references ae_domain(id); alter table ae_parameter add constraint fk_ae_parameter foreign key (parent_id) references ae_parameter(id); create sequence ae_state_seq cache 100; create table ae_state ( id number not null, res_id number not null, param_id number not null, value varchar2(300), datetime timestamp default current_timestamp not null ); comment on table ae_state is ' '; comment on column ae_state.datetime is '    '; create unique index ae_state_pk on ae_state(id); create index ae_state_res_fk on ae_state(res_id); create index ae_state_param_fk on ae_state(param_id); alter table ae_state add constraint pk_ae_state primary key(id); alter table ae_state add constraint fk_ae_state_res foreign key (res_id) references ae_resource(id); alter table ae_state add constraint fk_ae_state_param foreign key (param_id) references ae_parameter(id); create sequence ae_state_log_seq cache 100; create table ae_state_log ( id number not null, res_id number not null, param_id number not null, value varchar2(300), datetime timestamp default current_timestamp not null ) pctfree 0 partition by range (datetime) ( partition ae_state_log_p1 values less than (maxvalue) ); comment on table ae_state_log is '   '; create unique index ae_state_log_pk on ae_state_log(datetime, id) local; alter table ae_state_log add constraint pk_ae_state_log primary key(datetime, id); create sequence ae_profile_type_seq; create table ae_profile_type ( id number not null, name varchar2(30) not null, description varchar2(100) ); create unique index ae_profile_type_pk on ae_profile_type(id); create unique index ae_profile_type_uk on ae_profile_type(name); alter table ae_profile_type add constraint pk_ae_profile_type primary key(id); create sequence ae_profile_seq; create table ae_profile ( id number not null, type_id number not null, is_default number(1) default 0 not null, model_id number not null, script_id number default null, name varchar2(30) not null, description varchar2(100) ); create unique index ae_profile_pk on ae_profile(id); create index ae_profile_type_fk on ae_profile(type_id); create index ae_profile_model_fk on ae_profile(model_id); create index ae_profile_script_fk on ae_profile(script_id); alter table ae_profile add constraint ae_profile_ck check (is_default in (0, 1)); alter table ae_profile add constraint pk_ae_profile primary key(id); alter table ae_profile add constraint fk_ae_profile_type foreign key (type_id) references ae_profile_type(id); create sequence ae_profile_detail_seq; create table ae_profile_detail ( id number not null, type_id number not null, profile_id number not null, model_id number not null, param_id number not null ); create unique index ae_profile_detail_pk on ae_profile_detail(id); create index ae_profile_detail_fk on ae_profile_detail(profile_id); create index ae_profile_detail_type_fk on ae_profile_detail(type_id); create index ae_profile_detail_model_fk on ae_profile_detail(model_id); create index ae_profile_detail_param_fk on ae_profile_detail(param_id); alter table ae_profile_detail add constraint pk_ae_profile_detail primary key(id); alter table ae_profile_detail add constraint fk_ae_profile_detail foreign key (profile_id) references ae_profile(id); alter table ae_profile_detail add constraint fk_ae_profile_detail_type foreign key (type_id) references ae_resource_type(id); alter table ae_profile_detail add constraint fk_ae_profile_detail_model foreign key (model_id) references ae_platform_model(id); create global temporary table ae_state_tmp ( id number not null, device_id number not null, profile_id number not null, param_id number not null, num varchar2(300), value varchar2(300), datetime timestamp default current_timestamp not null ) on commit delete rows; create index ae_state_tmp_ix on ae_state_tmp(device_id, profile_id, param_id, num);
      
      







これで、ディレクトリをデヌタで埋めるこずができたす。



詊隓デヌタ
 Insert into AE_POLICY_TYPE (ID, NAME, DESCRIPTION) Values (1, 'default', NULL); Insert into AE_POLICY_TYPE (ID, NAME, DESCRIPTION) Values (2, 'uptime', NULL); Insert into AE_POLICY_TYPE (ID, NAME, DESCRIPTION) Values (3, 'threshold', NULL); COMMIT; Insert into AE_STATE_POLICY (ID, NAME, DESCRIPTION, TYPE_ID) Values (1, 'default', NULL, 1); Insert into AE_STATE_POLICY (ID, NAME, DESCRIPTION, TYPE_ID) Values (2, 'uptime', NULL, 2); COMMIT; Insert into AE_DOMAIN (ID, REGEXP, IS_CASE_SENS, DESCRIPTION, POLICY_ID) Values (10, '((\d+)\D*,\s*)?(\d+):(\d+):(\d+)(\.\d+)?', 0, 'SNMP uptime', 1); Insert into AE_DOMAIN (ID, REGEXP, IS_CASE_SENS, DESCRIPTION, POLICY_ID) Values (11, '\d+', 0, 'SNMP ', 1); Insert into AE_DOMAIN (ID, REGEXP, IS_CASE_SENS, DESCRIPTION, POLICY_ID) Values (12, '([a-fA-F\d])+', 0, 'SNMP ', 1); Insert into AE_DOMAIN (ID, REGEXP, IS_CASE_SENS, DESCRIPTION, POLICY_ID) Values (13, '.*', 0, 'SNMP  ', 1); Insert into AE_DOMAIN (ID, REGEXP, IS_CASE_SENS, DESCRIPTION, POLICY_ID) Values (14, '\d+', 0, 'SNMP uptime ( )', 2); COMMIT; Insert into AE_PARAMETER (ID, DOMAIN_ID, PARENT_ID, NAME, DESCRIPTION) Values (101, 14, NULL, 'uptime', 'SNMP Uptime'); Insert into AE_PARAMETER (ID, DOMAIN_ID, PARENT_ID, NAME, DESCRIPTION) Values (102, 11, NULL, 'ifIndex', ' '); Insert into AE_PARAMETER (ID, DOMAIN_ID, PARENT_ID, NAME, DESCRIPTION) Values (103, 13, NULL, 'ifName', ' '); Insert into AE_PARAMETER (ID, DOMAIN_ID, PARENT_ID, NAME, DESCRIPTION) Values (104, 11, NULL, 'ifInOctets', ' '); Insert into AE_PARAMETER (ID, DOMAIN_ID, PARENT_ID, NAME, DESCRIPTION) Values (105, 11, NULL, 'ifOutOctets', ' '); COMMIT; Insert into AE_PLATFORM_MODEL (ID, NAME, DESCRIPTION) Values (1, 'test', NULL); COMMIT; Insert into AE_PROFILE_TYPE (ID, NAME, DESCRIPTION) Values (1, 'mon', ''); COMMIT; Insert into AE_PROFILE (ID, TYPE_ID, IS_DEFAULT, MODEL_ID, SCRIPT_ID, NAME, DESCRIPTION) Values (1, 1, 1, 1, NULL, 'test', NULL); COMMIT; Insert into AE_RESOURCE_CLASS (ID, IS_LOGICAL, NAME, DESCRIPTION, OWNER_ID) Values (1, 0, '', NULL, NULL); Insert into AE_RESOURCE_CLASS (ID, IS_LOGICAL, NAME, DESCRIPTION, OWNER_ID) Values (2, 0, '', NULL, 1); COMMIT; Insert into AE_RESOURCE_TYPE (ID, CLASS_ID, NAME, DESCRIPTION, OWNER_ID, PARENT_ID) Values (1, 1, 'Host', NULL, NULL, NULL); Insert into AE_RESOURCE_TYPE (ID, CLASS_ID, NAME, DESCRIPTION, OWNER_ID, PARENT_ID) Values (2, 2, 'Interface', NULL, 1, NULL); COMMIT; Insert into AE_PROFILE_DETAIL (ID, TYPE_ID, PROFILE_ID, MODEL_ID, PARAM_ID) Values (4, 2, 1, 1, 104); Insert into AE_PROFILE_DETAIL (ID, TYPE_ID, PROFILE_ID, MODEL_ID, PARAM_ID) Values (5, 2, 1, 1, 105); Insert into AE_PROFILE_DETAIL (ID, TYPE_ID, PROFILE_ID, MODEL_ID, PARAM_ID) Values (6, 1, 1, 1, 1); Insert into AE_PROFILE_DETAIL (ID, TYPE_ID, PROFILE_ID, MODEL_ID, PARAM_ID) Values (1, 1, 1, 1, 101); Insert into AE_PROFILE_DETAIL (ID, TYPE_ID, PROFILE_ID, MODEL_ID, PARAM_ID) Values (2, 2, 1, 1, 102); Insert into AE_PROFILE_DETAIL (ID, TYPE_ID, PROFILE_ID, MODEL_ID, PARAM_ID) Values (3, 2, 1, 1, 103); COMMIT; Insert into AE_DEVICE (ID, MODEL_ID, START_DATE, END_DATE) Values (0, 1, TO_DATE('10/30/2013 15:37:16', 'MM/DD/YYYY HH24:MI:SS'), NULL); COMMIT; Insert into AE_RESOURCE (ID, DEVICE_ID, OWNER_ID, TYPE_ID, NAME, RES_NUM, RES_ID, START_DATE, END_DATE, TMP_ID) Values (1, 0, NULL, 1, '127.0.0.1', '0', NULL, TO_DATE('10/30/2013 15:24:44', 'MM/DD/YYYY HH24:MI:SS'), NULL, NULL); COMMIT; Insert into AE_THRESHOLD_TYPE (ID, NAME, DESCRIPTION) Values (1, 'increase', ''); Insert into AE_THRESHOLD_TYPE (ID, NAME, DESCRIPTION) Values (2, 'decrease', ''); Insert into AE_THRESHOLD_TYPE (ID, NAME, DESCRIPTION) Values (3, 'delta', ''); COMMIT; Insert into AE_THRESHOLD (ID, TYPE_ID, POLICY_ID, VALUE) Values (1, 3, 1, '100'); COMMIT;
      
      







そしお、テストコヌドのドラフトを準備したす。



テストコヌド
 package com.acme.ae.tests.jdbc; import oracle.jdbc.driver.OracleCallableStatement; import oracle.sql.*; import java.sql.CallableStatement; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; public class Test { private final static String CLASS_NAME = "oracle.jdbc.driver.OracleDriver"; private final static String USER_CONN = "jdbc:oracle:thin:@192.168.124.5:1523:new11"; private final static String USER_NAME = "ais"; private final static String USER_PASS = "ais"; private final static boolean AUTO_COMMIT_MODE = false; private final static int BULK_SIZE = 100; private final static int ALL_SIZE = 1000; private final static String TRACE_ON_SQL = "ALTER SESSION SET EVENTS '10046 trace name context forever, level 12'"; private final static Long DEVICE_ID = 0L; private final static Long PROFILE_ID = 1L; private final static Long UPTIME_PARAM_ID = 101L; private final static Long IFNAME_PARAM_ID = 103L; private final static Long INOCT_PARAM_ID = 104L; private final static String FAKE_NUM_VALUE = "0"; private Connection c = null; private void start() throws ClassNotFoundException, SQLException { Class.forName(CLASS_NAME); c = DriverManager.getConnection(USER_CONN, USER_NAME, USER_PASS); c.setAutoCommit(AUTO_COMMIT_MODE); CallableStatement st = c.prepareCall(TRACE_ON_SQL); try { st.execute(); } finally { st.close(); } } private void stop() throws SQLException { if (c != null) { c.close(); } } public static void main(String[] args) { Test t = new Test(); try { try { t.start(); t.test_plsql(); //      } finally { t.stop(); } } catch (Exception e) { System.out.println(e.toString()); } } }
      
      







パフォヌマンスの詳现な分析のために、サヌバヌ䞊のむベント10046トレヌスを䜿甚し、 tkprofナヌティリティによるトレヌスの埌続の凊理を行いたす。



最も遅い方法plsql



最も明癜な単䞀レコヌド凊理でテストを開始したす。 実際にパフォヌマンスを評䟡するこずに加えお、このコヌドを曞くこずで、デヌタの凊理方法をよりよく理解するこずができたす。



PL / SQLコヌド
 CREATE OR REPLACE package AIS.ae_monitoring as procedure addValue( p_device in number , p_profile in number , p_param in number , p_num in varchar2 , p_val in varchar2 ); end ae_monitoring; / CREATE OR REPLACE package body AIS.ae_monitoring as g_ifName_parameter constant number default 103; g_default_policy constant number default 1; g_uptime_policy constant number default 2; g_threshold_policy constant number default 3; g_increase_type constant number default 1; g_decrease_type constant number default 2; g_delta_type constant number default 3; procedure addValue( p_device in number , p_profile in number , p_param in number , p_num in varchar2 , p_val in varchar2 ) as cursor c_res(p_type number) is select r.id, r.name from ae_resource r where r.device_id = p_device and r.res_num = p_num and r.type_id = p_type and r.start_date <= sysdate and sysdate <= nvl(r.end_date, sysdate + 1); cursor c_state(p_resid number) is select s.value from ae_state s where s.res_id = p_resid and s.param_id = p_param; l_resid ae_resource.id%type default null; l_resname ae_resource.name%type default null; l_oldval ae_state.value%type default null; l_restype ae_profile_detail.type_id%type default null; l_owntype ae_resource_type.owner_id%type default null; l_owner ae_resource.id%type default null; l_policy ae_state_policy.type_id%type default null; l_polid ae_state_policy.id%type default null; l_count number default 0; begin --    select d.type_id, r.owner_id into l_restype, l_owntype from ae_profile_detail d inner join ae_resource_type r on (r.id = d.type_id) where d.profile_id = p_profile and d.param_id = p_param; --  ID  if not l_owntype is null then select r.id into l_owner from ae_resource r where r.device_id = p_device and r.type_id = l_owntype; end if; --    if p_param = g_ifName_parameter then open c_res(l_restype); fetch c_res into l_resid, l_resname; if c_res%notfound or l_resname <> p_val then --     update ae_resource set end_date = sysdate where id = l_resid; --     insert into ae_resource(id, device_id, owner_id, type_id, res_num, name) values (ae_resource_seq.nextval, p_device, l_owner, l_restype, p_num, p_val); end if; close c_res; return; end if; --  ID  open c_res(l_restype); fetch c_res into l_resid, l_resname; if c_res%notfound then --    ,     insert into ae_resource(id, device_id, owner_id, type_id, res_num, name) values (ae_resource_seq.nextval, p_device, l_owner, l_restype, p_num, p_val) returning id into l_resid; end if; --     open c_state(l_resid); fetch c_state into l_oldval; if c_state%notfound then l_oldval := null; end if; close c_state; --     select l.type_id, l.id into l_policy, l_polid from ae_parameter p inner join ae_domain d on (d.id = p.domain_id) inner join ae_state_policy l on (l.id = d.policy_id) where p.id = p_param; --     select count(*) into l_count from ae_threshold t where t.policy_id = l_polid and (( t.type_id = g_increase_type and l_oldval <= t.value and p_val >= t.value ) or ( t.type_id = g_decrease_type and l_oldval >= t.value and p_val <= t.value ) or ( t.type_id = g_delta_type and abs(p_val - l_oldval) >= t.value )); --    ae_state_log     if l_oldval is null or l_count > 0 or ( l_policy = g_uptime_policy and p_val < l_oldval) or ( l_policy = g_default_policy and p_val <> l_oldval) then insert into ae_state_log(id, res_id, param_id, value) values (ae_state_log_seq.nextval, l_resid, p_param, decode(l_policy, g_uptime_policy, nvl(l_oldval, p_val), p_val)); end if; --  ae_state update ae_state set value = p_val , datetime = current_timestamp where res_id = l_resid and param_id = p_param; if sql%rowcount = 0 then insert into ae_state(id, param_id, res_id, value) values (ae_state_seq.nextval, p_param, l_resid, p_val); end if; close c_res; exception when others then if c_res%isopen then close c_res; end if; if c_state%isopen then close c_state; end if; raise; end; end ae_monitoring; /
      
      







Javaコヌド
  private final static String ADD_VAL_SQL = "begin ae_monitoring.addValue(?,?,?,?,?); end;"; private void test_plsql() throws SQLException { System.out.println("test_plsql:"); CallableStatement st = c.prepareCall(ADD_VAL_SQL); Long timestamp = System.currentTimeMillis(); Long uptime = 0L; Long inoct = 0L; try { for (int i = 1; i <= ALL_SIZE; i++) { //  uptime st.setLong(1, DEVICE_ID); st.setLong(2, PROFILE_ID); st.setLong(3, UPTIME_PARAM_ID); st.setString(4, FAKE_NUM_VALUE); st.setString(5, uptime.toString()); st.execute(); //    st.setLong(1, DEVICE_ID); st.setLong(2, PROFILE_ID); st.setLong(3, IFNAME_PARAM_ID); st.setString(4, Integer.toString((i % 100) + 1)); st.setString(5, Integer.toString((i % 100) + 1)); st.execute(); //    st.setLong(1, DEVICE_ID); st.setLong(2, PROFILE_ID); st.setLong(3, INOCT_PARAM_ID); st.setString(4, Integer.toString((i % 100) + 1)); st.setString(5, inoct.toString()); st.execute(); //   uptime += 100L; if (uptime >= 1000) { uptime = 0L; } inoct += 10L; } } finally { st.close(); } Long delta_1 = System.currentTimeMillis() - timestamp; System.out.println((ALL_SIZE * 1000L) / delta_1); timestamp = System.currentTimeMillis(); c.commit(); Long delta_2 = System.currentTimeMillis() - timestamp; System.out.println(delta_2); System.out.println((ALL_SIZE * 1000L) / (delta_1 - delta_2)); }
      
      







明らかに、このコヌドがむンタヌフェむスのリストを正しくサポヌトするには、リ゜ヌスの他の属性の前にむンタヌフェむスの名前をデヌタベヌスに転送する必芁がありたす。



テスト結果は非垞に予枬可胜です



結果
 OVERALL TOTALS FOR ALL NON-RECURSIVE STATEMENTS call count cpu elapsed disk query current rows ------- ------ -------- ---------- ---------- ---------- ---------- ---------- Parse 1 0.00 0.00 0 0 0 0 Execute 3000 4.23 4.13 7 102942 6615 3000 Fetch 0 0.00 0.00 0 0 0 0 ------- ------ -------- ---------- ---------- ---------- ---------- ---------- total 3001 4.23 4.13 7 102942 6615 3000 Misses in library cache during parse: 1 Misses in library cache during execute: 1 Elapsed times include waiting on following events: Event waited on Times Max. Wait Total Waited ---------------------------------------- Waited ---------- ------------ SQL*Net message to client 3002 0.00 0.00 SQL*Net message from client 3002 5.92 7.12 latch: library cache 4 0.00 0.00 log file sync 1 0.00 0.00 OVERALL TOTALS FOR ALL RECURSIVE STATEMENTS call count cpu elapsed disk query current rows ------- ------ -------- ---------- ---------- ---------- ---------- ---------- Parse 69 0.00 0.00 0 0 0 0 Execute 17261 2.42 2.36 7 9042 6615 3160 Fetch 14000 0.38 0.37 0 93900 0 13899 ------- ------ -------- ---------- ---------- ---------- ---------- ---------- total 31330 2.81 2.74 7 102942 6615 17059 Misses in library cache during parse: 10 Misses in library cache during execute: 10 Elapsed times include waiting on following events: Event waited on Times Max. Wait Total Waited ---------------------------------------- Waited ---------- ------------ db file sequential read 7 0.00 0.00
      
      







非垞に倚くのリク゚ストを実行し、ネットワヌク通信に倚くの時間を費やしおいたす。



倧量凊理を䜿甚したす䞀時



オヌバヌヘッドに察凊する最も根本的な方法は、倧量凊理に移行するこずです。 たず、凊理のためにデヌタセットを䜕らかのテヌブルに保存し、次に1぀のレコヌドではなく䞀床にすべおのデヌタを凊理できたす。 もちろん、䞭間デヌタストレヌゞには通垞のテヌブルを䜿甚できたすが、ロギングのオヌバヌヘッドが削枛されるため、これらの目的でGTTを䜿甚する方がより有益です。



デヌタを䞀時テヌブルに挿入するには、ストアドプロシヌゞャの呌び出しではなくDMLを䜿甚したす。これにより、 JDBCバッチを䜿甚しおネットワヌクオヌバヌヘッドを削枛できたす。



このアプロヌチを䜿甚する堎合、他のパラメヌタヌの前にむンタヌフェむス名を凊理する必芁はありたせん。 凊理されたすべおのむンタヌフェヌスの名前が、凊理されたデヌタセットにあれば十分です。



PL / SQLコヌド
 CREATE OR REPLACE package AIS.ae_monitoring as procedure saveValues; end ae_monitoring; / CREATE OR REPLACE package body AIS.ae_monitoring as g_ifName_parameter constant number default 103; g_default_policy constant number default 1; g_uptime_policy constant number default 2; g_threshold_policy constant number default 3; g_increase_type constant number default 1; g_decrease_type constant number default 2; g_delta_type constant number default 3; procedure saveValues as begin --  ,    merge into ae_resource d using ( select t.id, t.device_id, t.num, t.value name, p.type_id, o.id owner_id from ae_state_tmp t inner join ae_profile_detail p on (p.profile_id = t.profile_id and p.param_id = t.param_id) inner join ae_resource_type r on (r.id = p.type_id) left join ae_resource o on (o.device_id = t.device_id and o.type_id = r.owner_id) where t.param_id = g_ifName_parameter ) s on ( d.device_id = s.device_id and d.res_num = s.num and d.type_id = s.type_id and d.start_date <= sysdate and sysdate <= nvl(d.end_date, sysdate + 1) ) when matched then update set d.tmp_id = s.id where d.name <> s.name when not matched then insert (id, device_id, owner_id, type_id, res_num, name) values (ae_resource_seq.nextval, s.device_id, s.owner_id, s.type_id, s.num, s.name); --   ae_resource insert into ae_resource(id, device_id, owner_id, type_id, res_num, name) select ae_resource_seq.nextval, t.device_id, o.id, p.type_id, t.num, t.value from ae_state_tmp t inner join ae_resource c on (c.tmp_id = t.id) inner join ae_profile_detail p on (p.profile_id = t.profile_id and p.param_id = t.param_id) inner join ae_resource_type r on (r.id = p.type_id) left join ae_resource o on (o.device_id = t.device_id and o.type_id = r.owner_id); --    update ae_resource set end_date = sysdate , tmp_id = null where tmp_id > 0; --    ae_state_log insert into ae_state_log(id, res_id, param_id, value) select ae_state_log_seq.nextval, id, param_id, value from ( select distinct r.id, t.param_id, decode(l.type_id, g_uptime_policy, nvl(s.value, t.value), t.value) value from ae_state_tmp t inner join ae_profile_detail p on (p.profile_id = t.profile_id and p.param_id = t.param_id) inner join ae_resource r on ( r.device_id = t.device_id and r.res_num = t.num and r.type_id = p.type_id and r.start_date <= sysdate and sysdate <= nvl(r.end_date, sysdate + 1)) left join ae_state s on (s.res_id = r.id and s.param_id = t.param_id) inner join ae_parameter a on (a.id = p.param_id) inner join ae_domain d on (d.id = a.domain_id) inner join ae_state_policy l on (l.id = d.policy_id) left join ae_threshold h on ( h.policy_id = l.id and (( h.type_id = g_increase_type and s.value <= h.value and t.value >= h.value ) or ( h.type_id = g_decrease_type and s.value >= h.value and t.value <= h.value ) or ( h.type_id = g_delta_type and abs(t.value - s.value) >= h.value ))) where ( s.id is null or not h.id is null or ( l.type_id = g_uptime_policy and t.value < s.value ) or ( l.type_id = g_default_policy and t.value <> s.value ) ) and t.param_id <> g_ifName_parameter ); --  ae_state merge into ae_state d using ( select t.param_id, t.value, r.id res_id from ae_state_tmp t inner join ae_profile_detail p on (p.profile_id = t.profile_id and p.param_id = t.param_id) inner join ae_resource r on ( r.device_id = t.device_id and r.res_num = t.num and r.type_id = p.type_id and r.start_date <= sysdate and sysdate <= nvl(r.end_date, sysdate + 1)) where t.param_id <> g_ifName_parameter ) s on (d.res_id = s.res_id and d.param_id = s.param_id) when matched then update set d.value = s.value , d.datetime = current_timestamp when not matched then insert (id, param_id, res_id, value) values (ae_state_seq.nextval, s.param_id, s.res_id, s.value); --   commit write nowait; end; end ae_monitoring; /
      
      







Javaコヌド
  private final static int BULK_SIZE = 200; private final static String INS_VAL_SQL = "insert into ae_state_tmp(id, device_id, profile_id, param_id, num, value) values (?,?,?,?,?,?)"; private final static String SAVE_VALUES_SQL = "begin ae_monitoring.saveValues; end;"; private void test_temporary() throws SQLException { System.out.println("test_temporary:"); CallableStatement st = c.prepareCall(INS_VAL_SQL); Long timestamp = System.currentTimeMillis(); Long uptime = 0L; Long inoct = 0L; Long ix = 1L; int bulk = BULK_SIZE; try { for (int i = 1; i <= ALL_SIZE; i++) { //  uptime st.setLong(1, ix++); st.setLong(2, DEVICE_ID); st.setLong(3, PROFILE_ID); st.setLong(4, UPTIME_PARAM_ID); st.setString(5, FAKE_NUM_VALUE); st.setString(6, uptime.toString()); st.addBatch(); //    st.setLong(1, ix++); st.setLong(2, DEVICE_ID); st.setLong(3, PROFILE_ID); st.setLong(4, IFNAME_PARAM_ID); st.setString(5, Integer.toString((i % 100) + 1)); st.setString(6, Integer.toString((i % 100) + 1)); st.addBatch(); //    st.setLong(1, ix++); st.setLong(2, DEVICE_ID); st.setLong(3, PROFILE_ID); st.setLong(4, INOCT_PARAM_ID); st.setString(5, Integer.toString((i % 100) + 1)); st.setString(6, inoct.toString()); st.addBatch(); if (--bulk <= 0) { st.executeBatch(); bulk = BULK_SIZE; } //   uptime += 100L; if (uptime >= 1000) { uptime = 0L; } inoct += 10L; } if (bulk < BULK_SIZE) { st.executeBatch(); } } finally { st.close(); } Long delta_1 = System.currentTimeMillis() - timestamp; System.out.println((ALL_SIZE * 1000L) / delta_1); timestamp = System.currentTimeMillis(); st = c.prepareCall(SAVE_VALUES_SQL); timestamp = System.currentTimeMillis(); try { st.execute(); } finally { st.close(); } Long delta_2 = System.currentTimeMillis() - timestamp; System.out.println(delta_2); System.out.println((ALL_SIZE * 1000L) / (delta_1 - delta_2)); }
      
      







このコヌドを実行しお、実行しお取埗したす。



 java.sql.SQLException: ORA-30926:         ORA-06512:  "AIS.AE_MONITORING", line 205 ORA-06512:  line 1
      
      





考えおみるず、この゚ラヌの理由が明らかになりたす。 凊理されたデヌタのセットに、いく぀かの倉数の競合するデヌタが含たれおいる堎合䜕回かそれを読み取った、問題が発生したす。 SNMP監芖の通垞の機胜では、この状況は発生したせんが、発生した堎合にアプリケヌションがクラッシュするのを防ぐために䜕かを提䟛する必芁がありたす。



最初に思い浮かぶのは、各倉数の集蚈デヌタを保存するこずです。 ただない堎合は新しいレコヌドを远加するか、既存のレコヌドを曎新し、新しい倀を曞き蟌みたす。



Javaコヌド
  private final static int BULK_SIZE = 200; private final static String MERGE_VAL_SQL = "merge into ae_state_tmp d " + "using ( select ? id,? device_id,? profile_id,? param_id,? num,? value " + " from dual" + " ) s " + "on ( d.device_id = s.device_id and d.profile_id = s.profile_id and " + " d.param_id = s.param_id and d.num = s.num ) " + "when matched then " + " update set d.value = s.value " + "when not matched then " + " insert (id, device_id, profile_id, param_id, num, value) " + " values (s.id, s.device_id, s.profile_id, s.param_id, s.num, s.value)"; private final static String SAVE_VALUES_SQL = "begin ae_monitoring.saveValues; end;"; private void test_temporary() throws SQLException { System.out.println("test_temporary:"); CallableStatement st = c.prepareCall(MERGE_VAL_SQL); ...
      
      







珟圚、同じ問題に察凊しおいたすが、バッチリク゚ストの段階で



 java.sql.BatchUpdateException: ORA-00600:   , : [6704], [2], [0], [6301696], [], [], [], [], [], [], [], []
      
      





私はバッチを攟棄しなければなりたせん



 private final static int BULK_SIZE = 1;
      
      





結果は著しく改善されたした



結果
 OVERALL TOTALS FOR ALL NON-RECURSIVE STATEMENTS call count cpu elapsed disk query current rows ------- ------ -------- ---------- ---------- ---------- ---------- ---------- Parse 2 0.00 0.00 0 0 0 0 Execute 1001 1.02 1.01 0 9002 3503 3001 Fetch 0 0.00 0.00 0 0 0 0 ------- ------ -------- ---------- ---------- ---------- ---------- ---------- total 1003 1.02 1.01 0 9002 3503 3001 Misses in library cache during parse: 1 Misses in library cache during execute: 1 Elapsed times include waiting on following events: Event waited on Times Max. Wait Total Waited ---------------------------------------- Waited ---------- ------------ SQL*Net message to client 1002 0.00 0.00 SQL*Net message from client 1002 0.00 0.41 log file sync 1 0.00 0.00 OVERALL TOTALS FOR ALL RECURSIVE STATEMENTS call count cpu elapsed disk query current rows ------- ------ -------- ---------- ---------- ---------- ---------- ---------- Parse 23 0.01 0.01 0 1 0 0 Execute 23 0.21 0.21 43 29392 348 111 Fetch 11 0.00 0.00 0 27 0 10 ------- ------ -------- ---------- ---------- ---------- ---------- ---------- total 57 0.22 0.23 43 29420 348 121 Misses in library cache during parse: 8 Misses in library cache during execute: 6 Elapsed times include waiting on following events: Event waited on Times Max. Wait Total Waited ---------------------------------------- Waited ---------- ------------ db file sequential read 41 0.01 0.01 db file scattered read 1 0.00 0.00
      
      







代替アプロヌチ個別



倧量凊理段階でグルヌプ化を远加するこずにより、デヌタ挿入の段階でORA-600機胜を取り陀くず同時に䜜業を簡玠化できたす。 この堎合、BULK_SIZEを恥ずかしがり屋にせず、最倧に蚭定したす。



PL / SQLコヌド
 CREATE OR REPLACE package AIS.ae_monitoring as procedure saveValuesDistinct; end ae_monitoring; / CREATE OR REPLACE package body AIS.ae_monitoring as g_ifName_parameter constant number default 103; g_default_policy constant number default 1; g_uptime_policy constant number default 2; g_threshold_policy constant number default 3; g_increase_type constant number default 1; g_decrease_type constant number default 2; g_delta_type constant number default 3; procedure saveValuesDistinct as begin --  ,    merge into ae_resource d using ( select t.id, t.device_id, t.num, t.value name, p.type_id, o.id owner_id from ( select device_id, profile_id, param_id, num , max(id) keep (dense_rank last order by datetime) id , max(value) keep (dense_rank last order by datetime) value , max(datetime) datetime from ae_state_tmp group by device_id, profile_id, param_id, num ) t inner join ae_profile_detail p on (p.profile_id = t.profile_id and p.param_id = t.param_id) inner join ae_resource_type r on (r.id = p.type_id) left join ae_resource o on (o.device_id = t.device_id and o.type_id = r.owner_id) where t.param_id = g_ifName_parameter ) s on ( d.device_id = s.device_id and d.res_num = s.num and d.type_id = s.type_id and d.start_date <= sysdate and sysdate <= nvl(d.end_date, sysdate + 1) ) when matched then update set d.tmp_id = s.id where d.name <> s.name when not matched then insert (id, device_id, owner_id, type_id, res_num, name) values (ae_resource_seq.nextval, s.device_id, s.owner_id, s.type_id, s.num, s.name); --   ae_resource insert into ae_resource(id, device_id, owner_id, type_id, res_num, name) select ae_resource_seq.nextval, t.device_id, o.id, p.type_id, t.num, t.value from ( select device_id, profile_id, param_id, num , max(id) keep (dense_rank last order by datetime) id , max(value) keep (dense_rank last order by datetime) value , max(datetime) datetime from ae_state_tmp group by device_id, profile_id, param_id, num ) t inner join ae_resource c on (c.tmp_id = t.id) inner join ae_profile_detail p on (p.profile_id = t.profile_id and p.param_id = t.param_id) inner join ae_resource_type r on (r.id = p.type_id) left join ae_resource o on (o.device_id = t.device_id and o.type_id = r.owner_id); --    update ae_resource set end_date = sysdate , tmp_id = null where tmp_id > 0; --    ae_state_log insert into ae_state_log(id, res_id, param_id, value) select ae_state_log_seq.nextval, id, param_id, value from ( select distinct r.id, t.param_id, decode(l.type_id, g_uptime_policy, nvl(s.value, t.value), t.value) value from ( select device_id, profile_id, param_id, num , max(id) keep (dense_rank last order by datetime) id , max(value) keep (dense_rank last order by datetime) value , max(datetime) datetime from ae_state_tmp group by device_id, profile_id, param_id, num ) t inner join ae_profile_detail p on (p.profile_id = t.profile_id and p.param_id = t.param_id) inner join ae_resource r on ( r.device_id = t.device_id and r.res_num = t.num and r.type_id = p.type_id and r.start_date <= sysdate and sysdate <= nvl(r.end_date, sysdate + 1)) left join ae_state s on (s.res_id = r.id and s.param_id = t.param_id) inner join ae_parameter a on (a.id = p.param_id) inner join ae_domain d on (d.id = a.domain_id) inner join ae_state_policy l on (l.id = d.policy_id) left join ae_threshold h on ( h.policy_id = l.id and (( h.type_id = g_increase_type and s.value <= h.value and t.value >= h.value ) or ( h.type_id = g_decrease_type and s.value >= h.value and t.value <= h.value ) or ( h.type_id = g_delta_type and abs(t.value - s.value) >= h.value ))) where ( s.id is null or not h.id is null or ( l.type_id = g_uptime_policy and t.value < s.value ) or ( l.type_id = g_default_policy and t.value <> s.value ) ) and t.param_id <> g_ifName_parameter ); --  ae_state merge into ae_state d using ( select t.param_id, t.value, r.id res_id from ( select device_id, profile_id, param_id, num , max(id) keep (dense_rank last order by datetime) id , max(value) keep (dense_rank last order by datetime) value , max(datetime) datetime from ae_state_tmp group by device_id, profile_id, param_id, num ) t inner join ae_profile_detail p on (p.profile_id = t.profile_id and p.param_id = t.param_id) inner join ae_resource r on ( r.device_id = t.device_id and r.res_num = t.num and r.type_id = p.type_id and r.start_date <= sysdate and sysdate <= nvl(r.end_date, sysdate + 1)) where t.param_id <> g_ifName_parameter ) s on (d.res_id = s.res_id and d.param_id = s.param_id) when matched then update set d.value = s.value , d.datetime = current_timestamp when not matched then insert (id, param_id, res_id, value) values (ae_state_seq.nextval, s.param_id, s.res_id, s.value); --   commit write nowait; end; end ae_monitoring; /
      
      







Javaコヌド
  private final static int BULK_SIZE = 200; private final static String INS_VAL_SQL = "insert into ae_state_tmp(id, device_id, profile_id, param_id, num, value) values (?,?,?,?,?,?)"; private final static String SAVE_VALUES_DISTINCT_SQL = "begin ae_monitoring.saveValuesDistinct; end;"; private void test_temporary_distinct() throws SQLException { System.out.println("test_temporary:"); CallableStatement st = c.prepareCall(INS_VAL_SQL); Long timestamp = System.currentTimeMillis(); Long uptime = 0L; Long inoct = 0L; Long ix = 1L; int bulk = BULK_SIZE; try { for (int i = 1; i <= ALL_SIZE; i++) { //  uptime st.setLong(1, ix++); st.setLong(2, DEVICE_ID); st.setLong(3, PROFILE_ID); st.setLong(4, UPTIME_PARAM_ID); st.setString(5, FAKE_NUM_VALUE); st.setString(6, uptime.toString()); st.addBatch(); //    st.setLong(1, ix++); st.setLong(2, DEVICE_ID); st.setLong(3, PROFILE_ID); st.setLong(4, IFNAME_PARAM_ID); st.setString(5, Integer.toString((i % 100) + 1)); st.setString(6, Integer.toString((i % 100) + 1)); st.addBatch(); //    st.setLong(1, ix++); st.setLong(2, DEVICE_ID); st.setLong(3, PROFILE_ID); st.setLong(4, INOCT_PARAM_ID); st.setString(5, Integer.toString((i % 100) + 1)); st.setString(6, inoct.toString()); st.addBatch(); if (--bulk <= 0) { st.executeBatch(); bulk = BULK_SIZE; } //   uptime += 100L; if (uptime >= 1000) { uptime = 0L; } inoct += 10L; } if (bulk < BULK_SIZE) { st.executeBatch(); } } finally { st.close(); } Long delta_1 = System.currentTimeMillis() - timestamp; System.out.println((ALL_SIZE * 1000L) / delta_1); timestamp = System.currentTimeMillis(); st = c.prepareCall(SAVE_VALUES_DISTINCT_SQL); timestamp = System.currentTimeMillis(); try { st.execute(); } finally { st.close(); } Long delta_2 = System.currentTimeMillis() - timestamp; System.out.println(delta_2); System.out.println((ALL_SIZE * 1000L) / (delta_1 - delta_2)); }
      
      







起動しお結果を確認したす。



結果
 OVERALL TOTALS FOR ALL NON-RECURSIVE STATEMENTS call count cpu elapsed disk query current rows ------- ------ -------- ---------- ---------- ---------- ---------- ---------- Parse 2 0.00 0.00 0 0 0 0 Execute 1001 0.36 0.33 0 96 6616 3001 Fetch 0 0.00 0.00 0 0 0 0 ------- ------ -------- ---------- ---------- ---------- ---------- ---------- total 1003 0.36 0.33 0 96 6616 3001 Misses in library cache during parse: 2 Misses in library cache during execute: 1 Elapsed times include waiting on following events: Event waited on Times Max. Wait Total Waited ---------------------------------------- Waited ---------- ------------ SQL*Net message to client 1002 0.00 0.00 SQL*Net message from client 1002 0.00 0.41 log file sync 1 0.00 0.00 OVERALL TOTALS FOR ALL RECURSIVE STATEMENTS call count cpu elapsed disk query current rows ------- ------ -------- ---------- ---------- ---------- ---------- ---------- Parse 30 0.01 0.01 0 3 0 0 Execute 30 0.41 0.40 3 48932 1104 218 Fetch 8 0.00 0.00 0 176 0 8 ------- ------ -------- ---------- ---------- ---------- ---------- ---------- total 68 0.44 0.43 3 49111 1104 226 Misses in library cache during parse: 8 Misses in library cache during execute: 7 Elapsed times include waiting on following events: Event waited on Times Max. Wait Total Waited ---------------------------------------- Waited ---------- ------------ db file sequential read 3 0.00 0.00
      
      







予想どおり、デヌタを挿入するコストは枛少したしたが、その埌の凊理はより耇雑になりたした。



コレクションを䜿甚したすコレクション



DenKrepが正しく述べたように、デヌタを挿入するコストを可胜な限り䜎くしおも、GTTアプロヌチは空から空ぞ泚ぐプロセスに非垞に䌌おいたす。他にどのようにネットワヌキングのコストを削枛できたすかJDBCバッチを䜿甚しおPL / SQLコヌドを呌び出すこずはできたせんたたは、できたすが、メリットはありたせんが、配列を枡すこずはできたす



Javaコヌド自䜓から配列を枡すプロセスに぀いおは、このガむドで詳しく説明しおいたす。デヌタを転送するには、次のタむプを決定する必芁がありたす。



 create or replace type ae_state_rec as object ( device_id number, profile_id number, param_id number, num varchar2(300), value varchar2(300) ) / create or replace type ae_state_tab as table of ae_state_rec; /
      
      





Oracle Client 11gがむンストヌルされおいるため、[ORACLE_HOME] /jdbc/lib/classes12.zipを[ORACLE_HOME] /jdbc/lib/ojdbc5.jarに眮き換える必芁がありたした。たた、アプリケヌションの起動時に[ORACLE_HOME] /jdbc/lib/nls_charset12.zipが䜿甚可胜でなければならないこずを匷調したいず思いたす。



サヌバヌでアレむをどのように凊理したすか開始するには、前にルヌプで䜜成されたaddValueを呌び出しおみおください。



  ... procedure addValues( p_tab in ae_state_tab ) as begin for i in 1 .. p_tab.count loop addValue( p_device => p_tab(i).device_id , p_profile => p_tab(i).profile_id , p_param => p_tab(i).param_id , p_num => p_tab(i).num , p_val => p_tab(i).value ); end loop; commit write nowait; end; ...
      
      





Javaコヌドは著しく耇雑です。



Javaコヌド
  private final static String ADD_VALUES_SQL = "begin ae_monitoring.addValues(?); end;"; private void test_collection() throws SQLException { System.out.println("test_collection:"); OracleCallableStatement st = (OracleCallableStatement)c.prepareCall(ADD_VALUES_SQL); int oracleId = CharacterSet.CL8MSWIN1251_CHARSET; CharacterSet charSet = CharacterSet.make(oracleId); Long timestamp = System.currentTimeMillis(); Long uptime = 0L; Long inoct = 0L; RecType r[] = new RecType[ALL_SIZE * 3]; int ix = 0; for (int i = 1; i <= ALL_SIZE; i++) { //  uptime r[ix++] = new RecType( new NUMBER(DEVICE_ID), new NUMBER(PROFILE_ID), new NUMBER(UPTIME_PARAM_ID), new CHAR(FAKE_NUM_VALUE, charSet), new CHAR(uptime.toString(), charSet)); //    r[ix++] = new RecType( new NUMBER(DEVICE_ID), new NUMBER(PROFILE_ID), new NUMBER(IFNAME_PARAM_ID), new CHAR(Integer.toString((i % 100) + 1), charSet), new CHAR(Integer.toString((i % 100) + 1), charSet)); //    r[ix++] = new RecType( new NUMBER(DEVICE_ID), new NUMBER(PROFILE_ID), new NUMBER(INOCT_PARAM_ID), new CHAR(Integer.toString((i % 100) + 1), charSet), new CHAR(inoct.toString(), charSet)); //   uptime += 100L; if (uptime >= 1000) { uptime = 0L; } inoct += 10L; } RecTab t = new RecTab(r); try { st.setORAData(1, t); st.execute(); } finally { st.close(); } System.out.println((ALL_SIZE * 1000L) / (System.currentTimeMillis() - timestamp)); }
      
      









クラむアントからの配列の転送に関連するトレヌスには、さたざたな面癜い挔算子が衚瀺されたす。



 SELECT INSTANTIABLE, supertype_owner, supertype_name, LOCAL_ATTRIBUTES FROM all_types WHERE type_name = :1 AND owner = :2
      
      





結果は論理的です



結果
 OVERALL TOTALS FOR ALL NON-RECURSIVE STATEMENTS call count cpu elapsed disk query current rows ------- ------ -------- ---------- ---------- ---------- ---------- ---------- Parse 4 0.00 0.00 0 0 0 0 Execute 4 4.35 4.31 5 136053 6610 3 Fetch 1 0.00 0.00 0 9 0 1 ------- ------ -------- ---------- ---------- ---------- ---------- ---------- total 9 4.35 4.31 5 136062 6610 4 Misses in library cache during parse: 2 Misses in library cache during execute: 2 Elapsed times include waiting on following events: Event waited on Times Max. Wait Total Waited ---------------------------------------- Waited ---------- ------------ SQL*Net message to client 6 0.00 0.00 SQL*Net message from client 6 0.23 0.34 SQL*Net more data from client 41 0.00 0.00 OVERALL TOTALS FOR ALL RECURSIVE STATEMENTS call count cpu elapsed disk query current rows ------- ------ -------- ---------- ---------- ---------- ---------- ---------- Parse 77 0.00 0.00 0 0 0 0 Execute 17270 2.97 2.92 5 6046 6610 3160 Fetch 14013 0.49 0.49 1 129930 0 13909 ------- ------ -------- ---------- ---------- ---------- ---------- ---------- total 31360 3.48 3.43 6 135976 6610 17069 Misses in library cache during parse: 8 Misses in library cache during execute: 11 Elapsed times include waiting on following events: Event waited on Times Max. Wait Total Waited ---------------------------------------- Waited ---------- ------------ db file sequential read 6 0.00 0.00
      
      







クラむアントからのデヌタ転送に関連するむンゞケヌタは改善されたしたが、デヌタ凊理はplsqlオプションに比べおやや耇雑になりたした。



賢いコレクションを䜿甚したすバルク



明らかに、クラむアントから送信された配列の可胜性を完党に利甚しおいるわけではありたせん。配列をSQLク゚リに盎接枡しお䞀括凊理を有効にするず䟿利ですが、その方法はク゚リが耇雑すぎるため、BULK COLLECTを䜿甚できたせん。幞いなこずに、コレクションをTABLEでラップできたす。



PL / SQLコヌド
 CREATE OR REPLACE package AIS.ae_monitoring as procedure saveValues( p_tab in ae_state_tab ); end ae_monitoring; / CREATE OR REPLACE package body AIS.ae_monitoring as g_ifName_parameter constant number default 103; g_default_policy constant number default 1; g_uptime_policy constant number default 2; g_threshold_policy constant number default 3; g_increase_type constant number default 1; g_decrease_type constant number default 2; g_delta_type constant number default 3; procedure saveValues( p_tab in ae_state_tab ) as begin --  ,    merge into ae_resource d using ( select t.device_id, t.num, t.value name, p.type_id, o.id owner_id from ( select device_id, profile_id, param_id, num , max(value) value from table( p_tab ) group by device_id, profile_id, param_id, num ) t inner join ae_profile_detail p on (p.profile_id = t.profile_id and p.param_id = t.param_id) inner join ae_resource_type r on (r.id = p.type_id) left join ae_resource o on (o.device_id = t.device_id and o.type_id = r.owner_id) where t.param_id = g_ifName_parameter ) s on ( d.device_id = s.device_id and d.res_num = s.num and d.type_id = s.type_id and d.start_date <= sysdate and sysdate <= nvl(d.end_date, sysdate + 1) ) when not matched then insert (id, device_id, owner_id, type_id, res_num, name) values (ae_resource_seq.nextval, s.device_id, s.owner_id, s.type_id, s.num, s.name); --    ae_state_log insert into ae_state_log(id, res_id, param_id, value) select ae_state_log_seq.nextval, id, param_id, value from ( select distinct r.id, t.param_id, decode(l.type_id, g_uptime_policy, nvl(s.value, t.value), t.value) value from ( select device_id, profile_id, param_id, num , max(value) value from table( p_tab ) group by device_id, profile_id, param_id, num ) t inner join ae_profile_detail p on (p.profile_id = t.profile_id and p.param_id = t.param_id) inner join ae_resource r on ( r.device_id = t.device_id and r.res_num = t.num and r.type_id = p.type_id and r.start_date <= sysdate and sysdate <= nvl(r.end_date, sysdate + 1)) left join ae_state s on (s.res_id = r.id and s.param_id = t.param_id) inner join ae_parameter a on (a.id = p.param_id) inner join ae_domain d on (d.id = a.domain_id) inner join ae_state_policy l on (l.id = d.policy_id) left join ae_threshold h on ( h.policy_id = l.id and (( h.type_id = g_increase_type and s.value <= h.value and t.value >= h.value ) or ( h.type_id = g_decrease_type and s.value >= h.value and t.value <= h.value ) or ( h.type_id = g_delta_type and abs(t.value - s.value) >= h.value ))) where ( s.id is null or not h.id is null or ( l.type_id = g_uptime_policy and t.value < s.value ) or ( l.type_id = g_default_policy and t.value <> s.value ) ) and t.param_id <> g_ifName_parameter ); --  ae_state merge into ae_state d using ( select t.param_id, t.value, r.id res_id from ( select device_id, profile_id, param_id, num , max(value) value from table( p_tab ) group by device_id, profile_id, param_id, num ) t inner join ae_profile_detail p on (p.profile_id = t.profile_id and p.param_id = t.param_id) inner join ae_resource r on ( r.device_id = t.device_id and r.res_num = t.num and r.type_id = p.type_id and r.start_date <= sysdate and sysdate <= nvl(r.end_date, sysdate + 1)) where t.param_id <> g_ifName_parameter ) s on (d.res_id = s.res_id and d.param_id = s.param_id) when matched then update set d.value = s.value , d.datetime = current_timestamp when not matched then insert (id, param_id, res_id, value) values (ae_state_seq.nextval, s.param_id, s.res_id, s.value); --   commit write nowait; end; end ae_monitoring; /
      
      







Javaコヌド
  private final static String BULK_VALUES_SQL = "begin ae_monitoring.saveValues(?); end;"; private void test_bulk() throws SQLException { System.out.println("test_bulk:"); OracleCallableStatement st = (OracleCallableStatement)c.prepareCall(BULK_VALUES_SQL); int oracleId = CharacterSet.CL8MSWIN1251_CHARSET; CharacterSet charSet = CharacterSet.make(oracleId); Long timestamp = System.currentTimeMillis(); Long uptime = 0L; Long inoct = 0L; RecType r[] = new RecType[ALL_SIZE * 3]; int ix = 0; for (int i = 1; i <= ALL_SIZE; i++) { //  uptime r[ix++] = new RecType( new NUMBER(DEVICE_ID), new NUMBER(PROFILE_ID), new NUMBER(UPTIME_PARAM_ID), new CHAR(FAKE_NUM_VALUE, charSet), new CHAR(uptime.toString(), charSet)); //    r[ix++] = new RecType( new NUMBER(DEVICE_ID), new NUMBER(PROFILE_ID), new NUMBER(IFNAME_PARAM_ID), new CHAR(Integer.toString((i % 100) + 1), charSet), new CHAR(Integer.toString((i % 100) + 1), charSet)); //    r[ix++] = new RecType( new NUMBER(DEVICE_ID), new NUMBER(PROFILE_ID), new NUMBER(INOCT_PARAM_ID), new CHAR(Integer.toString((i % 100) + 1), charSet), new CHAR(inoct.toString(), charSet)); //   uptime += 100L; if (uptime >= 1000) { uptime = 0L; } inoct += 10L; } RecTab t = new RecTab(r); try { st.setORAData(1, t); st.execute(); } finally { st.close(); } System.out.println((ALL_SIZE * 1000L) / (System.currentTimeMillis() - timestamp)); }
      
      







結果はそれ自身を物語っおいたす



結果
 OVERALL TOTALS FOR ALL NON-RECURSIVE STATEMENTS call count cpu elapsed disk query current rows ------- ------ -------- ---------- ---------- ---------- ---------- ---------- Parse 4 0.00 0.00 0 0 0 0 Execute 4 0.20 0.20 4 696 1095 3 Fetch 1 0.00 0.00 0 9 0 1 ------- ------ -------- ---------- ---------- ---------- ---------- ---------- total 9 0.20 0.20 4 705 1095 4 Misses in library cache during parse: 0 Elapsed times include waiting on following events: Event waited on Times Max. Wait Total Waited ---------------------------------------- Waited ---------- ------------ SQL*Net message to client 6 0.00 0.00 SQL*Net message from client 6 0.10 0.19 SQL*Net more data from client 41 0.00 0.00 OVERALL TOTALS FOR ALL RECURSIVE STATEMENTS call count cpu elapsed disk query current rows ------- ------ -------- ---------- ---------- ---------- ---------- ---------- Parse 30 0.00 0.00 0 0 0 0 Execute 38 0.18 0.17 4 591 1095 217 Fetch 46 0.00 0.00 0 96 0 30 ------- ------ -------- ---------- ---------- ---------- ---------- ---------- total 114 0.18 0.18 4 687 1095 247 Misses in library cache during parse: 7 Misses in library cache during execute: 7 Elapsed times include waiting on following events: Event waited on Times Max. Wait Total Waited ---------------------------------------- Waited ---------- ------------ db file sequential read 4 0.00 0.00
      
      







結論



テスト結果が瀺すように、クラむアントコヌドバルクからOracleぞの配列の盎接転送により、最高のパフォヌマンスを実珟できたす。GTT䞀時的、個別を䜿甚したバリアントは、パフォヌマンスの点ではそれほど劣りたせんが、Javaコヌドの芳点からははるかに単玔です。さらに、䞀時オプションを䜿甚するず、バッチず星の配眮が䞍適切な堎合にORA-600を芳察できたす。



デヌタ凊理に䜿甚するアプロヌチはナヌザヌ次第です。テスト結果はGitHubに投皿されたす。




All Articles