- التسجيل التلقائي للترجمة
- ماذا تفعل إذا كنت تريد إنشاء عرض مع المعلمات
- استخدام الإحصائيات الديناميكية في الاستعلامات
- كيفية حفظ خطة الاستعلام عند إدخال البيانات عبر ارتباط قاعدة البيانات
- تشغيل الإجراءات في جلسات متوازية
- سحب بقايا الطعام
- الجمع بين عدة قصص في قصة واحدة
- عادي
- التقديم بتنسيق SVG
- تطبيق Oracle Metadata Search
التسجيل التلقائي للترجمة
في بعض قواعد بيانات Oracle ، يوجد في Sberbank مشغل تجميع يتذكر من ومتى وما تغير في كود كائنات الخادم. وبالتالي ، يمكن تحديد مؤلف التغييرات من جدول سجل التجميع. يتم أيضًا تنفيذ نظام التحكم في الإصدار تلقائيًا. على أي حال ، إذا نسي المبرمج إرسال التغييرات إلى Git ، فستعمل هذه الآلية على التحوط. دعنا نصف مثالاً على تنفيذ مثل هذا النظام من التسجيل التلقائي للترجمة. يبدو أحد الإصدارات المبسطة لمشغل الترجمة الذي يكتب في السجل في شكل جدول ddl_changes_log كما يلي:
create table DDL_CHANGES_LOG
(
id INTEGER,
change_date DATE,
sid VARCHAR2(100),
schemaname VARCHAR2(30),
machine VARCHAR2(100),
program VARCHAR2(100),
osuser VARCHAR2(100),
obj_owner VARCHAR2(30),
obj_type VARCHAR2(30),
obj_name VARCHAR2(30),
previous_version CLOB,
changes_script CLOB
);
create or replace trigger trig_audit_ddl_trg
before ddl on database
declare
v_sysdate date;
v_valid number;
v_previous_obj_owner varchar2(30) := '';
v_previous_obj_type varchar2(30) := '';
v_previous_obj_name varchar2(30) := '';
v_previous_change_date date;
v_lob_loc_old clob := '';
v_lob_loc_new clob := '';
v_n number;
v_sql_text ora_name_list_t;
v_sid varchar2(100) := '';
v_schemaname varchar2(30) := '';
v_machine varchar2(100) := '';
v_program varchar2(100) := '';
v_osuser varchar2(100) := '';
begin
v_sysdate := sysdate;
-- find whether compiled object already presents and is valid
select count(*)
into v_valid
from sys.dba_objects
where owner = ora_dict_obj_owner
and object_type = ora_dict_obj_type
and object_name = ora_dict_obj_name
and status = 'VALID'
and owner not in ('SYS', 'SPOT', 'WMSYS', 'XDB', 'SYSTEM')
and object_type in ('TRIGGER', 'PROCEDURE', 'FUNCTION', 'PACKAGE', 'PACKAGE BODY', 'VIEW');
-- find information about previous compiled object
select max(obj_owner) keep(dense_rank last order by id),
max(obj_type) keep(dense_rank last order by id),
max(obj_name) keep(dense_rank last order by id),
max(change_date) keep(dense_rank last order by id)
into v_previous_obj_owner, v_previous_obj_type, v_previous_obj_name, v_previous_change_date
from ddl_changes_log;
-- if compile valid object or compile invalid package body broken by previous compilation of package then log it
if (v_valid = 1 or v_previous_obj_owner = ora_dict_obj_owner and
(v_previous_obj_type = 'PACKAGE' and ora_dict_obj_type = 'PACKAGE BODY' or
v_previous_obj_type = 'PACKAGE BODY' and ora_dict_obj_type = 'PACKAGE') and
v_previous_obj_name = ora_dict_obj_name and
v_sysdate - v_previous_change_date <= 1 / 24 / 60 / 2) and
ora_sysevent in ('CREATE', 'ALTER') then
-- store previous version of object (before compilation) from dba_source or dba_views in v_lob_loc_old
if ora_dict_obj_type <> 'VIEW' then
for z in (select substr(text, 1, length(text) - 1) || chr(13) || chr(10) as text
from sys.dba_source
where owner = ora_dict_obj_owner
and type = ora_dict_obj_type
and name = ora_dict_obj_name
order by line) loop
v_lob_loc_old := v_lob_loc_old || z.text;
end loop;
else
select sys.dbms_metadata_util.long2clob(v.textlength, 'SYS.VIEW$', 'TEXT', v.rowid) into v_lob_loc_old
from sys."_CURRENT_EDITION_OBJ" o, sys.view$ v, sys.user$ u
where o.obj# = v.obj#
and o.owner# = u.user#
and u.name = ora_dict_obj_owner
and o.name = ora_dict_obj_name;
end if;
-- store new version of object (after compilation) from v_sql_text in v_lob_loc_new
v_n := ora_sql_txt(v_sql_text);
for i in 1 .. v_n loop
v_lob_loc_new := v_lob_loc_new || replace(v_sql_text(i), chr(10), chr(13) || chr(10));
end loop;
-- find information about session that changed this object
select max(to_char(sid)), max(schemaname), max(machine), max(program), max(osuser)
into v_sid, v_schemaname, v_machine, v_program, v_osuser
from v$session
where audsid = userenv('sessionid');
-- store changes in ddl_changes_log
insert into ddl_changes_log
(id, change_date, sid, schemaname, machine, program, osuser,
obj_owner, obj_type, obj_name, previous_version, changes_script)
values
(seq_ddl_changes_log.nextval, v_sysdate, v_sid, v_schemaname, v_machine, v_program, v_osuser,
ora_dict_obj_owner, ora_dict_obj_type, ora_dict_obj_name, v_lob_loc_old, v_lob_loc_new);
end if;
exception
when others then
null;
end;
في هذا المشغل ، يتم الحصول على الاسم والمحتويات الجديدة للكائن المترجم ، مع استكمالها بالمحتويات السابقة من قاموس البيانات ، وكتابتها في سجل التغيير.
ماذا تفعل إذا كنت تريد إنشاء عرض مع المعلمات
غالبًا ما يمكن لمطور في Oracle زيارة هذه الرغبة. لماذا من الممكن إنشاء إجراء أو وظيفة باستخدام معلمات ، ولكن لا توجد طرق عرض بمعلمات إدخال يمكن استخدامها في الحسابات؟ لدى Oracle شيء ليحل محل هذا المفهوم المفقود ، في رأينا.
لنلقي نظرة على مثال. يجب ألا يكون هناك جدول بالمبيعات حسب القسم لكل يوم.
create table DIVISION_SALES
(
division_id INTEGER,
dt DATE,
sales_amt NUMBER
);
يقارن هذا الاستعلام المبيعات حسب القسم على مدار يومين. في هذه الحالة ، 04/30/2020 و 09/11/2020.
select t1.division_id,
t1.dt dt1,
t2.dt dt2,
t1.sales_amt sales_amt1,
t2.sales_amt sales_amt2
from (select dt, division_id, sales_amt
from division_sales
where dt = to_date('30.04.2020', 'dd.mm.yyyy')) t1,
(select dt, division_id, sales_amt
from division_sales
where dt = to_date('11.09.2020', 'dd.mm.yyyy')) t2
where t1.division_id = t2.division_id;
إليكم وجهة نظر أود كتابتها لتلخيص مثل هذا الطلب. أود تمرير التواريخ كمعلمات. ومع ذلك ، فإن بناء الجملة لا يسمح بذلك.
create or replace view vw_division_sales_report(in_dt1 date, in_dt2 date) as
select t1.division_id,
t1.dt dt1,
t2.dt dt2,
t1.sales_amt sales_amt1,
t2.sales_amt sales_amt2
from (select dt, division_id, sales_amt
from division_sales
where dt = in_dt1) t1,
(select dt, division_id, sales_amt
from division_sales
where dt = in_dt2) t2
where t1.division_id = t2.division_id;
تم اقتراح مثل هذا الحل. لنقم بإنشاء نوع للخط من هذا العرض.
create type t_division_sales_report as object
(
division_id INTEGER,
dt1 DATE,
dt2 DATE,
sales_amt1 NUMBER,
sales_amt2 NUMBER
);
وسننشئ نوعًا لجدول من هذه السلاسل.
create type t_division_sales_report_table as table of t_division_sales_report;
بدلاً من طريقة العرض ، دعنا نكتب دالة مخططة مع معلمات إدخال التاريخ.
create or replace function func_division_sales(in_dt1 date, in_dt2 date)
return t_division_sales_report_table
pipelined as
begin
for z in (select t1.division_id,
t1.dt dt1,
t2.dt dt2,
t1.sales_amt sales_amt1,
t2.sales_amt sales_amt2
from (select dt, division_id, sales_amt
from division_sales
where dt = in_dt1) t1,
(select dt, division_id, sales_amt
from division_sales
where dt = in_dt2) t2
where t1.division_id = t2.division_id) loop
pipe row(t_division_sales_report(z.division_id,
z.dt1,
z.dt2,
z.sales_amt1,
z.sales_amt2));
end loop;
end;
يمكنك الرجوع إليها على النحو التالي:
select *
from table(func_division_sales(to_date('30.04.2020', 'dd.mm.yyyy'),
to_date('11.09.2020', 'dd.mm.yyyy')));
سيعطينا هذا الطلب نفس نتيجة الطلب في بداية هذا المنشور بتواريخ بديلة صريحة.
يمكن أن تكون الوظائف المخططة مفيدة أيضًا عندما تحتاج إلى تمرير معلمة داخل استعلام معقد.
على سبيل المثال ، ضع في اعتبارك طريقة عرض معقدة يكون فيها الحقل 1 ، الذي تريد تصفية البيانات بواسطته ، مخفيًا في مكان ما في عمق العرض.
create or replace view complex_view as
select field1, ...
from (select field1, ...
from (select field1, ... from deep_table), table1
where ...),
table2
where ...;
وقد يكون للاستعلام من طريقة عرض ذات قيمة ثابتة لـ field1 خطة تنفيذ سيئة.
select field1, ... from complex_view
where field1 = 'myvalue';
أولئك. بدلاً من التصفية الأولى لـ deep_table بواسطة حقل الشرط 1 = "myvalue" ، يمكن للاستعلام أولاً ضم جميع الجداول ومعالجة كمية كبيرة من البيانات غير الضرورية ، ثم تصفية النتيجة حسب الحقل الشرط 1 = "myvalue". يمكن تجنب هذا التعقيد إذا قمنا بدلاً من العرض المبني على خطوط الأنابيب بإنشاء وظيفة بمعامل يتم تعيين قيمته للحقل 1.
استخدام الإحصائيات الديناميكية في الاستعلامات
يحدث أن نفس الاستعلام في قاعدة بيانات Oracle يعالج في كل مرة كمية مختلفة من البيانات في الجداول والاستعلامات الفرعية المستخدمة فيها. كيف يمكنك جعل المُحسِّن يكتشف طريقة ربط الجداول هذه المرة والفهارس التي يجب استخدامها في كل مرة؟ ضع في اعتبارك ، على سبيل المثال ، استعلامًا يربط جزءًا من أرصدة الحسابات التي تغيرت منذ آخر تنزيل إلى دليل الحساب. يختلف جزء أرصدة الحسابات المتغيرة اختلافًا كبيرًا من تنزيل إلى تنزيل ، حيث يصل إلى مئات الأسطر ، وأحيانًا ملايين السطور. اعتمادًا على حجم هذا الجزء ، يلزم دمج الأرصدة المتغيرة مع الحسابات إما عن طريق / * + use_nl * / طريقة ، أو عن طريق طريقة / * + use_hash * /. من غير الملائم إعادة تجميع الإحصائيات في كل مرة ، خاصةً إذا تغير عدد الصفوف من تحميل إلى تحميل ليس في الجدول المرتبط ، ولكن في الاستعلام الفرعي المرتبط.يمكن للتلميح / * + dynamic_sampling () * / أن ينقذ هنا. دعنا نظهر كيف يؤثر ذلك ، باستخدام طلب مثال. دع الجدول change_balances يحتوي على التغييرات في الأرصدة والحسابات - دليل الحسابات. ننضم إلى هذه الجداول من خلال حقول account_id المتوفرة في كل من الجداول. في بداية التجربة ، سنكتب المزيد من الصفوف في هذه الجداول ولن نغير محتوياتها.
أولاً ، لنأخذ 10٪ من التغييرات في القيم المتبقية في جدول change_balances ونرى ما الذي ستستخدمه الخطة Dynamic_sampling:
SQL> EXPLAIN PLAN
2 SET statement_id = 'test1'
3 INTO plan_table
4 FOR with c as
5 (select /*+ dynamic_sampling(change_balances 2)*/
6 account_id, balance_amount
7 from change_balances
8 where mod(account_id, 10) = 0)
9 select a.account_id, a.account_number, c.balance_amount
10 from c, accounts a
11 where c.account_id = a.account_id;
Explained.
SQL>
SQL> SELECT * FROM table (DBMS_XPLAN.DISPLAY);
Plan hash value: 874320301
----------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
----------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 9951K| 493M| | 140K (1)| 00:28:10 |
|* 1 | HASH JOIN | | 9951K| 493M| 3240K| 140K (1)| 00:28:10 |
|* 2 | TABLE ACCESS FULL| CHANGE_BALANCES | 100K| 2057K| | 7172 (1)| 00:01:27 |
| 3 | TABLE ACCESS FULL| ACCOUNTS | 10M| 295M| | 113K (1)| 00:22:37 |
----------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("ACCOUNT_ID"="A"."ACCOUNT_ID")
2 - filter(MOD("ACCOUNT_ID",10)=0)
Note
-----
- dynamic sampling used for this statement (level=2)
20 rows selected.
لذلك ، نرى أنه من المقترح المرور عبر جداول change_balances والحسابات باستخدام مسح كامل والانضمام إليها باستخدام صلة تجزئة.
الآن دعونا نقلل بشكل كبير من العينة من change_balances. لنأخذ 0.1٪ من التغييرات المتبقية ونرى ما ستستخدمه الخطة Dynamic_sampling:
SQL> EXPLAIN PLAN
2 SET statement_id = 'test2'
3 INTO plan_table
4 FOR with c as
5 (select /*+ dynamic_sampling(change_balances 2)*/
6 account_id, balance_amount
7 from change_balances
8 where mod(account_id, 1000) = 0)
9 select a.account_id, a.account_number, c.balance_amount
10 from c, accounts a
11 where c.account_id = a.account_id;
Explained.
SQL>
SQL> SELECT * FROM table (DBMS_XPLAN.DISPLAY);
Plan hash value: 2360715730
-------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 73714 | 3743K| 16452 (1)| 00:03:18 |
| 1 | NESTED LOOPS | | | | | |
| 2 | NESTED LOOPS | | 73714 | 3743K| 16452 (1)| 00:03:18 |
|* 3 | TABLE ACCESS FULL | CHANGE_BALANCES | 743 | 15603 | 7172 (1)| 00:01:27 |
|* 4 | INDEX RANGE SCAN | IX_ACCOUNTS_ACCOUNT_ID | 104 | | 2 (0)| 00:00:01 |
| 5 | TABLE ACCESS BY INDEX ROWID| ACCOUNTS | 99 | 3069 | 106 (0)| 00:00:02 |
-------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - filter(MOD("ACCOUNT_ID",1000)=0)
4 - access("ACCOUNT_ID"="A"."ACCOUNT_ID")
Note
-----
- dynamic sampling used for this statement (level=2)
22 rows selected.
في هذه المرة ، يتم إرفاق جدول الحسابات بجدول change_balances باستخدام حلقات متداخلة ويتم استخدام فهرس لقراءة الصفوف من الحسابات.
إذا تمت إزالة تلميح dynamic_sampling ، ففي الحالة الثانية ستبقى الخطة كما هي في الحالة الأولى ، وهذا ليس هو الأمثل.
يمكن العثور على تفاصيل حول تلميح dynamic_sampling والقيم المحتملة لوسيطته الرقمية في الوثائق.
كيفية حفظ خطة الاستعلام عند إدخال البيانات عبر ارتباط قاعدة البيانات
نحن نحل هذه المشكلة. يحتوي خادم مصدر البيانات على جداول يلزم ربطها وتحميلها في مستودع البيانات. لنفترض أن العرض مكتوب على الخادم المصدر ، والذي يحتوي على كل منطق تحويل ETL الضروري. تمت كتابة العرض على النحو الأمثل ، ويحتوي على تلميحات للمحسن تقترح كيفية ربط الجداول والفهارس التي يجب استخدامها. على جانب الخادم في مستودع البيانات ، عليك أن تفعل شيئًا بسيطًا - أدخل البيانات من العرض في الجدول الهدف. وهنا يمكن أن تنشأ صعوبات. إذا أدخلت في الجدول الهدف باستخدام أمر مثل
insert into dwh_table
(field1, field2)
select field1, field2 from vw_for_dwh_table@xe_link;
، ثم يمكن تجاهل كل منطق خطة الاستعلام الواردة في طريقة العرض التي نقرأ منها البيانات عبر رابط قاعدة البيانات. يمكن تجاهل كل التلميحات المضمنة في هذا العرض.
SQL> EXPLAIN PLAN
2 SET statement_id = 'test'
3 INTO plan_table
4 FOR insert into dwh_table
5 (field1, field2)
6 select field1, field2 from vw_for_dwh_table@xe_link;
Explained.
SQL>
SQL> SELECT * FROM table (DBMS_XPLAN.DISPLAY);
Plan hash value: 1788691278
-------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Inst |IN-OUT|
-------------------------------------------------------------------------------------------------------------
| 0 | INSERT STATEMENT | | 1 | 2015 | 2 (0)| 00:00:01 | | |
| 1 | LOAD TABLE CONVENTIONAL | DWH_TABLE | | | | | | |
| 2 | REMOTE | VW_FOR_DWH_TABLE | 1 | 2015 | 2 (0)| 00:00:01 | XE_LI~ | R->S |
-------------------------------------------------------------------------------------------------------------
Remote SQL Information (identified by operation id):
----------------------------------------------------
2 - SELECT /*+ OPAQUE_TRANSFORM */ "FIELD1","FIELD2" FROM "VW_FOR_DWH_TABLE" "VW_FOR_DWH_TABLE"
(accessing 'XE_LINK' )
16 rows selected.
لحفظ خطة الاستعلام في طريقة العرض ، يمكنك استخدام إدراج البيانات في الجدول الهدف من المؤشر:
declare
cursor cr is
select field1, field2 from vw_for_dwh_table@xe_link;
cr_row cr%rowtype;
begin
open cr;
loop
fetch cr
into cr_row;
insert into dwh_table
(field1, field2)
values
(cr_row.field1, cr_row.field2);
exit when cr%notfound;
end loop;
close cr;
end;
استعلام من المؤشر
select field1, field2 from vw_for_dwh_table@xe_link;
على عكس الإدراج
insert into dwh_table
(field1, field2)
select field1, field2 from vw_for_dwh_table@xe_link;
سيحفظ خطة الطلب الموضوعة في العرض على الخادم المصدر.
تشغيل الإجراءات في جلسات متوازية
غالبًا ما تكون المهمة هي بدء عدة عمليات حسابية متوازية من بعض الإجراءات الأبوية ، وبعد انتظار اكتمال كل منها ، استمر في تنفيذ الإجراء الأصلي. يمكن أن يكون هذا مفيدًا في الحوسبة المتوازية إذا سمحت موارد الخادم بذلك. هناك طرق عديدة للقيام بذلك.
دعونا نصف تنفيذًا بسيطًا جدًا لمثل هذه الآلية. سيتم تنفيذ الإجراءات الموازية في وظائف متوازية "لمرة واحدة" ، بينما سينتظر الإجراء الأصلي في حلقة لإكمال جميع هذه الوظائف.
لنقم بإنشاء جداول مع بيانات وصفية لهذه الآلية. بادئ ذي بدء ، دعنا نصنع جدولًا بمجموعات من إجراءات التشغيل المتوازي:
create table PARALLEL_PROC_GROUP_LIST
(
group_id INTEGER,
group_name VARCHAR2(4000)
);
comment on column PARALLEL_PROC_GROUP_LIST.group_id
is ' ';
comment on column PARALLEL_PROC_GROUP_LIST.group_name
is ' ';
بعد ذلك ، سننشئ جدولًا يحتوي على نصوص سيتم تنفيذها بالتوازي في مجموعات. يمكن أن يكون ملء هذا الجدول ثابتًا أو يتم إنشاؤه ديناميكيًا:
create table PARALLEL_PROC_LIST
(
group_id INTEGER,
proc_script VARCHAR2(4000),
is_active CHAR(1) default 'Y'
);
comment on column PARALLEL_PROC_LIST.group_id
is ' ';
comment on column PARALLEL_PROC_LIST.proc_script
is 'Pl/sql ';
comment on column PARALLEL_PROC_LIST.is_active
is 'Y - active, N - inactive. ';
وسنقوم بعمل جدول سجل ، حيث سنجمع سجلًا بالإجراء الذي تم بدء العمل فيه:
create table PARALLEL_PROC_LOG
(
run_id INTEGER,
group_id INTEGER,
proc_script VARCHAR2(4000),
job_id INTEGER,
start_time DATE,
end_time DATE
);
comment on column PARALLEL_PROC_LOG.run_id
is ' run_in_parallel';
comment on column PARALLEL_PROC_LOG.group_id
is ' ';
comment on column PARALLEL_PROC_LOG.proc_script
is 'Pl/sql ';
comment on column PARALLEL_PROC_LOG.job_id
is 'Job_id , ';
comment on column PARALLEL_PROC_LOG.start_time
is ' ';
comment on column PARALLEL_PROC_LOG.end_time
is ' ';
create sequence Seq_Parallel_Proc_Log;
الآن دعنا نعطي رمز الإجراء لبدء التدفقات المتوازية:
create or replace procedure run_in_parallel(in_group_id integer) as
-- parallel_proc_list.
-- - parallel_proc_list
v_run_id integer;
v_job_id integer;
v_job_id_list varchar2(32767);
v_job_id_list_ext varchar2(32767);
v_running_jobs_count integer;
begin
select seq_parallel_proc_log.nextval into v_run_id from dual;
-- submit jobs with the same parallel_proc_list.in_group_id
-- store seperated with ',' JOB_IDs in v_job_id_list
v_job_id_list := null;
v_job_id_list_ext := null;
for z in (select pt.proc_script
from parallel_proc_list pt
where pt.group_id = in_group_id
and pt.is_active = 'Y') loop
dbms_job.submit(v_job_id, z.proc_script);
insert into parallel_proc_log
(run_id, group_id, proc_script, job_id, start_time, end_time)
values
(v_run_id, in_group_id, z.proc_script, v_job_id, sysdate, null);
v_job_id_list := v_job_id_list || ',' || to_char(v_job_id);
v_job_id_list_ext := v_job_id_list_ext || ' union all select ' ||
to_char(v_job_id) || ' job_id from dual';
end loop;
commit;
v_job_id_list := substr(v_job_id_list, 2);
v_job_id_list_ext := substr(v_job_id_list_ext, 12);
-- loop while not all jobs finished
loop
-- set parallel_proc_log.end_time for finished jobs
execute immediate 'update parallel_proc_log set end_time = sysdate where job_id in (' ||
v_job_id_list_ext ||
' minus select job from user_jobs where job in (' ||
v_job_id_list ||
') minus select job_id from parallel_proc_log where job_id in (' ||
v_job_id_list || ') and end_time is not null)';
commit;
-- check whether all jobs finished
execute immediate 'select count(1) from user_jobs where job in (' ||
v_job_id_list || ')'
into v_running_jobs_count;
-- if all jobs finished then exit
exit when v_running_jobs_count = 0;
-- sleep a little
sys.dbms_lock.sleep(0.1);
end loop;
end;
دعنا نتحقق من كيفية عمل الإجراء run_in_parallel. لنقم بإنشاء إجراء اختبار نسميه في جلسات متوازية.
create or replace procedure sleep(in_seconds integer) as
begin
sys.Dbms_Lock.Sleep(in_seconds);
end;
دعنا نملأ اسم المجموعة والجدول بالبرامج النصية التي سيتم تنفيذها بالتوازي.
insert into PARALLEL_PROC_GROUP_LIST(group_id, group_name) values(1, ' ');
insert into PARALLEL_PROC_LIST(group_id, proc_script, is_active) values(1, 'begin sleep(5); end;', 'Y');
insert into PARALLEL_PROC_LIST(group_id, proc_script, is_active) values(1, 'begin sleep(10); end;', 'Y');
لنبدأ مجموعة من الإجراءات المتوازية.
begin
run_in_parallel(1);
end;
عند الانتهاء ، دعونا نرى السجل.
select * from PARALLEL_PROC_LOG;
| RUN_ID | معرف مجموعة | PROC_SCRIPT | JOB_ID | وقت البدء | وقت النهاية |
| 1 | 1 | تبدأ النوم (5) ؛ النهاية؛ | 1 | 09/11/2020 15:00:51 | 09/11/2020 15:00:56 |
| 1 | 1 | يبدأ النوم (10) ؛ النهاية؛ | 2 | 09/11/2020 15:00:51 | 09/11/2020 15:01:01 |
نرى أن وقت تنفيذ حالات إجراء الاختبار يلبي التوقعات.
سحب بقايا الطعام
دعونا نصف البديل لحل مشكلة مصرفية نموذجية إلى حد ما "سحب التوازن". لنفترض أن هناك جدولاً بحقائق التغييرات في أرصدة الحسابات. مطلوب للإشارة إلى رصيد الحساب الجاري لكل يوم من أيام التقويم (آخر يوم في اليوم). غالبًا ما تكون هناك حاجة إلى مثل هذه المعلومات في مستودعات البيانات. إذا لم تكن هناك حركات في العد في يوم ما ، فأنت بحاجة إلى تكرار آخر الباقي المعروف. إذا كانت كمية البيانات وقوة الحوسبة للخادم تسمح بذلك ، فيمكنك حل هذه المشكلة باستخدام استعلام SQL ، دون اللجوء إلى PL / SQL. ستساعدنا الدالة last_value (* تجاهل القيم الخالية) على (التقسيم حسب * الترتيب حسب *) في هذا الأمر ، والتي ستمتد آخر الباقي المعروف إلى التواريخ اللاحقة التي لم تحدث فيها تغييرات.
لنقم بإنشاء جدول ونملأه ببيانات الاختبار.
create table ACCOUNT_BALANCE
(
dt DATE,
account_id INTEGER,
balance_amt NUMBER,
turnover_amt NUMBER
);
comment on column ACCOUNT_BALANCE.dt
is ' ';
comment on column ACCOUNT_BALANCE.account_id
is ' ';
comment on column ACCOUNT_BALANCE.balance_amt
is ' ';
comment on column ACCOUNT_BALANCE.turnover_amt
is ' ';
insert into account_balance(dt, account_id, balance_amt, turnover_amt) values(to_date('01.01.2020 00:00:00','dd.mm.yyyy hh24.mi.ss'), 1, 23, 23);
insert into account_balance(dt, account_id, balance_amt, turnover_amt) values(to_date('05.01.2020 01:00:00','dd.mm.yyyy hh24.mi.ss'), 1, 45, 22);
insert into account_balance(dt, account_id, balance_amt, turnover_amt) values(to_date('05.01.2020 20:00:00','dd.mm.yyyy hh24.mi.ss'), 1, 44, -1);
insert into account_balance(dt, account_id, balance_amt, turnover_amt) values(to_date('05.01.2020 00:00:00','dd.mm.yyyy hh24.mi.ss'), 2, 67, 67);
insert into account_balance(dt, account_id, balance_amt, turnover_amt) values(to_date('05.01.2020 20:00:00','dd.mm.yyyy hh24.mi.ss'), 2, 77, 10);
insert into account_balance(dt, account_id, balance_amt, turnover_amt) values(to_date('07.01.2020 00:00:00','dd.mm.yyyy hh24.mi.ss'), 2, 72, -5);
الاستعلام أدناه يحل مشكلتنا. يحتوي الاستعلام الفرعي "cld" على تقويم التواريخ ، في الاستعلام الفرعي "ab" نقوم بتجميع أرصدة كل يوم ، في الاستعلام الفرعي "أ" نتذكر قائمة جميع الحسابات وتاريخ بدء السجل لكل حساب ، في الاستعلام الفرعي "قبل" لكل حساب نقوم بتكوين تقويم بالأيام من بدايته قصص. يضيف الطلب الأخير الأرصدة الأخيرة لكل يوم إلى تقويم الأيام النشطة لكل حساب ويمدها إلى الأيام التي لم تكن هناك تغييرات فيها.
with cld as
(select /*+ materialize*/
to_date('01.01.2020', 'dd.mm.yyyy') + level - 1 dt
from dual
connect by level <= 10),
ab as
(select trunc(dt) dt,
account_id,
max(balance_amt) keep(dense_rank last order by dt) balance_amt,
sum(turnover_amt) turnover_amt
from account_balance
group by trunc(dt), account_id),
a as
(select min(dt) min_dt, account_id from ab group by account_id),
pre as
(select cld.dt, a.account_id from cld left join a on cld.dt >= a.min_dt)
select pre.dt,
pre.account_id,
last_value(ab.balance_amt ignore nulls) over(partition by pre.account_id order by pre.dt) balance_amt,
nvl(ab.turnover_amt, 0) turnover_amt
from pre
left join ab
on pre.dt = ab.dt
and pre.account_id = ab.account_id
order by 2, 1;
نتيجة الاستعلام كما هو متوقع.
| DT | ACCOUNT_ID | BALANCE_AMT | TURNOVER_AMT |
| 01.01.2020 | 1 | 23 | 23 |
| 02.01.2020 | 1 | 23 | 0 |
| 03/01/2020 | 1 | 23 | 0 |
| 04/01/2020 | 1 | 23 | 0 |
| 01/05/2020 | 1 | 44 | 21 |
| 06.01.2020 | 1 | 44 | 0 |
| 07.01.2020 | 1 | 44 | 0 |
| 01/08/2020 | 1 | 44 | 0 |
| 09/01/2020 | 1 | 44 | 0 |
| 10.01.2020 | 1 | 44 | 0 |
| 01/05/2020 | 2 | 77 | 77 |
| 06.01.2020 | 2 | 77 | 0 |
| 07.01.2020 | 2 | 72 | -خمسة |
| 01/08/2020 | 2 | 72 | 0 |
| 09/01/2020 | 2 | 72 | 0 |
| 10.01.2020 | 2 | 72 | 0 |
الجمع بين عدة قصص في قصة واحدة
عند تحميل البيانات في المخازن ، غالبًا ما يتم حل المشكلة عندما تحتاج إلى إنشاء سجل واحد لكيان ما ، مع وجود سجل منفصل لسمات هذا الكيان التي تأتي من مصادر مختلفة. لنفترض أن هناك كيانًا له مفتاح أساسي primary_key_id ، والذي يُعرف عنه التاريخ (start_dt - end_dt) لسماته الثلاثة المختلفة ، الموجود في ثلاثة جداول مختلفة.
create table HIST1
(
primary_key_id INTEGER,
start_dt DATE,
attribute1 NUMBER
);
insert into HIST1(primary_key_id, start_dt, attribute1) values(1, to_date('2014-01-01','yyyy-mm-dd'), 7);
insert into HIST1(primary_key_id, start_dt, attribute1) values(1, to_date('2015-01-01','yyyy-mm-dd'), 8);
insert into HIST1(primary_key_id, start_dt, attribute1) values(1, to_date('2016-01-01','yyyy-mm-dd'), 9);
insert into HIST1(primary_key_id, start_dt, attribute1) values(2, to_date('2014-01-01','yyyy-mm-dd'), 17);
insert into HIST1(primary_key_id, start_dt, attribute1) values(2, to_date('2015-01-01','yyyy-mm-dd'), 18);
insert into HIST1(primary_key_id, start_dt, attribute1) values(2, to_date('2016-01-01','yyyy-mm-dd'), 19);
create table HIST2
(
primary_key_id INTEGER,
start_dt DATE,
attribute2 NUMBER
);
insert into HIST2(primary_key_id, start_dt, attribute2) values(1, to_date('2015-01-01','yyyy-mm-dd'), 4);
insert into HIST2(primary_key_id, start_dt, attribute2) values(1, to_date('2016-01-01','yyyy-mm-dd'), 5);
insert into HIST2(primary_key_id, start_dt, attribute2) values(1, to_date('2017-01-01','yyyy-mm-dd'), 6);
insert into HIST2(primary_key_id, start_dt, attribute2) values(2, to_date('2015-01-01','yyyy-mm-dd'), 14);
insert into HIST2(primary_key_id, start_dt, attribute2) values(2, to_date('2016-01-01','yyyy-mm-dd'), 15);
insert into HIST2(primary_key_id, start_dt, attribute2) values(2, to_date('2017-01-01','yyyy-mm-dd'), 16);
create table HIST3
(
primary_key_id INTEGER,
start_dt DATE,
attribute3 NUMBER
);
insert into HIST3(primary_key_id, start_dt, attribute3) values(1, to_date('2016-01-01','yyyy-mm-dd'), 10);
insert into HIST3(primary_key_id, start_dt, attribute3) values(1, to_date('2017-01-01','yyyy-mm-dd'), 20);
insert into HIST3(primary_key_id, start_dt, attribute3) values(1, to_date('2018-01-01','yyyy-mm-dd'), 30);
insert into HIST3(primary_key_id, start_dt, attribute3) values(2, to_date('2016-01-01','yyyy-mm-dd'), 110);
insert into HIST3(primary_key_id, start_dt, attribute3) values(2, to_date('2017-01-01','yyyy-mm-dd'), 120);
insert into HIST3(primary_key_id, start_dt, attribute3) values(2, to_date('2018-01-01','yyyy-mm-dd'), 130);
الهدف هو تحميل سجل تغيير واحد من ثلاث سمات في جدول واحد.
يوجد أدناه استعلام يحل هذه المشكلة. يقوم أولاً بتكوين جدول قطري q1 مع بيانات من مصادر مختلفة لسمات مختلفة (تمتلئ السمات الغائبة في المصدر بالقيم الخالية). بعد ذلك ، باستخدام الدالة last_value (* تجاهل القيم الخالية) ، يتم طي الجدول المائل في سجل واحد ، ويتم تمديد آخر قيم السمات المعروفة إلى التواريخ التي لم تكن هناك تغييرات فيها:
select primary_key_id,
start_dt,
nvl(lead(start_dt - 1)
over(partition by primary_key_id order by start_dt),
to_date('9999-12-31', 'yyyy-mm-dd')) as end_dt,
last_value(attribute1 ignore nulls) over(partition by primary_key_id order by start_dt) as attribute1,
last_value(attribute2 ignore nulls) over(partition by primary_key_id order by start_dt) as attribute2,
last_value(attribute3 ignore nulls) over(partition by primary_key_id order by start_dt) as attribute3
from (select primary_key_id,
start_dt,
max(attribute1) as attribute1,
max(attribute2) as attribute2,
max(attribute3) as attribute3
from (select primary_key_id,
start_dt,
attribute1,
cast(null as number) attribute2,
cast(null as number) attribute3
from hist1
union all
select primary_key_id,
start_dt,
cast(null as number) attribute1,
attribute2,
cast(null as number) attribute3
from hist2
union all
select primary_key_id,
start_dt,
cast(null as number) attribute1,
cast(null as number) attribute2,
attribute3
from hist3) q1
group by primary_key_id, start_dt) q2
order by primary_key_id, start_dt;
النتيجة هكذا:
| PRIMARY_KEY_ID | START_DT | END_DT | السمة 1 | السمة 2 | السمة 3 |
| 1 | 01/01/2014 | 12/31/2014 | 7 | لا شيء | لا شيء |
| 1 | 01.01.2015 | 31.12.2015 | 8 | 4 | لا شيء |
| 1 | 01/2016 | 31/12/2016 | تسع | خمسة | عشرة |
| 1 | 01.01.2017 | 31.12.2017 | تسع | 6 | 20 |
| 1 | 01.01.2018 | 31/12/1999 م | تسع | 6 | ثلاثين |
| 2 | 01/01/2014 | 12/31/2014 | 17 | لا شيء | لا شيء |
| 2 | 01.01.2015 | 31.12.2015 | الثامنة عشر | أربعة عشرة | لا شيء |
| 2 | 01/2016 | 31/12/2016 | 19 | خمسة عشر | 110 |
| 2 | 01.01.2017 | 31.12.2017 | 19 | السادس عشر | 120 |
| 2 | 01.01.2018 | 31/12/1999 م | 19 | السادس عشر | 130 |
عادي
في بعض الأحيان تنشأ مشكلة تطبيع البيانات التي تأتي في شكل حقل محدد. على سبيل المثال ، في شكل جدول مثل هذا:
create table DENORMALIZED_TABLE
(
id INTEGER,
val VARCHAR2(4000)
);
insert into DENORMALIZED_TABLE(id, val) values(1, 'aaa,cccc,bb');
insert into DENORMALIZED_TABLE(id, val) values(2, 'ddd');
insert into DENORMALIZED_TABLE(id, val) values(3, 'fffff,e');
يعمل هذا الاستعلام على تسوية البيانات عن طريق لصق الحقول المرتبطة بفاصلة كسطر متعددة:
select id, regexp_substr(val, '[^,]+', 1, column_value) val, column_value
from denormalized_table,
table(cast(multiset
(select level
from dual
connect by regexp_instr(val, '[^,]+', 1, level) > 0) as
sys.odcinumberlist))
order by id, column_value;
النتيجة هكذا:
| هوية شخصية | VAL | COLUMN_VALUE |
| 1 | aaa | 1 |
| 1 | cccc | 2 |
| 1 | ب | 3 |
| 2 | ddd | 1 |
| 3 | fffff | 1 |
| 3 | ه | 2 |
التقديم بتنسيق SVG
غالبًا ما تكون هناك رغبة في تصور المؤشرات الرقمية المخزنة في قاعدة البيانات بطريقة ما. على سبيل المثال ، قم بإنشاء الرسوم البيانية والرسوم البيانية والمخططات. يمكن أن تساعد الأدوات المتخصصة مثل Oracle BI. ولكن قد تكلف تراخيص هذه الأدوات أموالاً ، وقد يستغرق إعدادها وقتًا أطول من كتابة استعلام SQL "على الركبة" إلى Oracle ، والذي سيعيد الصورة النهائية. دعنا نوضح بمثال كيفية رسم مثل هذه الصورة بسرعة بتنسيق SVG باستخدام استعلام.
افترض أن لدينا جدولاً بالبيانات
create table graph_data(dt date, val number, radius number);
insert into graph_data(dt, val, radius) values (to_date('01.01.2020','dd.mm.yyyy'), 12, 3);
insert into graph_data(dt, val, radius) values (to_date('02.01.2020','dd.mm.yyyy'), 15, 4);
insert into graph_data(dt, val, radius) values (to_date('05.01.2020','dd.mm.yyyy'), 17, 5);
insert into graph_data(dt, val, radius) values (to_date('06.01.2020','dd.mm.yyyy'), 13, 6);
insert into graph_data(dt, val, radius) values (to_date('08.01.2020','dd.mm.yyyy'), 3, 7);
insert into graph_data(dt, val, radius) values (to_date('10.01.2020','dd.mm.yyyy'), 20, 8);
insert into graph_data(dt, val, radius) values (to_date('11.01.2020','dd.mm.yyyy'), 18, 9);
dt هو تاريخ الصلة ،
val هو مؤشر رقمي ، ديناميكيات نتخيلها بمرور الوقت ،
نصف القطر هو مؤشر رقمي آخر سنرسمه في شكل دائرة بنصف قطر كهذا.
دعنا نقول بضع كلمات عن تنسيق SVG. إنه تنسيق رسومات متجه يمكن عرضه في المتصفحات الحديثة وتحويله إلى تنسيقات رسوم أخرى. في ذلك ، من بين أشياء أخرى ، يمكنك رسم خطوط ودوائر وكتابة نص:
<line x1="94" x2="94" y1="15" y2="675" style="stroke:rgb(150,255,255); stroke-width:1px"/>
<circle cx="30" cy="279" r="3" style="fill:rgb(255,0,0)"/>
<text x="7" y="688" font-size="10" fill="rgb(0,150,255)">2020-01-01</text>
يوجد أدناه استعلام SQL إلى Oracle الذي يرسم رسمًا بيانيًا من البيانات الموجودة في هذا الجدول. هنا يحتوي الاستعلام الفرعي const على إعدادات ثابتة متنوعة - حجم الصورة ، وعدد الملصقات على محاور الرسم البياني ، وألوان الخطوط والدوائر ، وأحجام الخطوط ، إلخ. في طلب البحث الفرعي gd1 ، نقوم بتحويل البيانات من جدول Graph_data إلى إحداثيات x و y في الشكل. يتذكر طلب البحث الفرعي gd2 النقاط السابقة في الوقت المناسب ، والتي يجب من خلالها رسم الخطوط إلى نقاط جديدة. كتلة "الرأس" هي رأس الصورة بخلفية بيضاء. كتلة "الخطوط العمودية" ترسم خطوطًا عمودية. تواريخ تسميات الكتل "التواريخ تحت الأسطر الرأسية" على المحور السيني. كتلة "الخطوط الأفقية" ترسم خطوطًا أفقية. تسمي كتلة "القيم بالقرب من الخطوط الأفقية" القيم الموجودة على المحور ص. ترسم كتلة "الدوائر" دوائر نصف القطر المحدد في جدول Graph_data.تُنشئ كتلة "بيانات الرسم البياني" رسمًا بيانيًا لديناميكيات مؤشر val من جدول بيانات الرسم البياني من الخطوط. تضيف كتلة "التذييل" علامة لاحقة.
with const as
(select 700 viewbox_width,
700 viewbox_height,
30 left_margin,
30 right_margin,
15 top_margin,
25 bottom_margin,
max(dt) - min(dt) + 1 num_vertical_lines,
11 num_horizontal_lines,
'rgb(150,255,255)' stroke_vertical_lines,
'1px' stroke_width_vertical_lines,
10 font_size_dates,
'rgb(0,150,255)' fill_dates,
23 x_dates_pad,
13 y_dates_pad,
'rgb(150,255,255)' stroke_horizontal_lines,
'1px' stroke_width_horizontal_lines,
10 font_size_values,
'rgb(0,150,255)' fill_values,
4 x_values_pad,
2 y_values_pad,
'rgb(255,0,0)' fill_circles,
'rgb(51,102,0)' stroke_graph,
'1px' stroke_width_graph,
min(dt) min_dt,
max(dt) max_dt,
max(val) max_val
from graph_data),
gd1 as
(select graph_data.dt,
const.left_margin +
(const.viewbox_width - const.left_margin - const.right_margin) *
(graph_data.dt - const.min_dt) / (const.max_dt - const.min_dt) x,
const.viewbox_height - const.bottom_margin -
(const.viewbox_height - const.top_margin - const.bottom_margin) *
graph_data.val / const.max_val y,
graph_data.radius
from graph_data, const),
gd2 as
(select dt,
round(nvl(lag(x) over(order by dt), x)) prev_x,
round(x) x,
round(nvl(lag(y) over(order by dt), y)) prev_y,
round(y) y,
radius
from gd1)
/* header */
select '<?xml version="1.0" encoding="UTF-8" standalone="no"?>' txt
from dual
union all
select '<svg version="1.1" width="' || viewbox_width || '" height="' ||
viewbox_height || '" viewBox="0 0 ' || viewbox_width || ' ' ||
viewbox_height ||
'" style="background:yellow" baseProfile="full" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:ev="http://www.w3.org/2001/xml-events">'
from const
union all
select '<title>Test graph</title>'
from dual
union all
select '<desc>Test graph</desc>'
from dual
union all
select '<rect width="' || viewbox_width || '" height="' || viewbox_height ||
'" style="fill:white" />'
from const
union all
/* vertical lines */
select '<line x1="' ||
to_char(round(left_margin +
(viewbox_width - left_margin - right_margin) *
(level - 1) / (num_vertical_lines - 1))) || '" x2="' ||
to_char(round(left_margin +
(viewbox_width - left_margin - right_margin) *
(level - 1) / (num_vertical_lines - 1))) || '" y1="' ||
to_char(round(top_margin)) || '" y2="' ||
to_char(round(viewbox_height - bottom_margin)) || '" style="stroke:' ||
const.stroke_vertical_lines || '; stroke-width:' ||
const.stroke_width_vertical_lines || '"/>'
from const
connect by level <= num_vertical_lines
union all
/* dates under vertical lines */
select '<text x="' ||
to_char(round(left_margin +
(viewbox_width - left_margin - right_margin) *
(level - 1) / (num_vertical_lines - 1) - x_dates_pad)) ||
'" y="' ||
to_char(round(viewbox_height - bottom_margin + y_dates_pad)) ||
'" font-size="' || font_size_dates || '" fill="' || fill_dates || '">' ||
to_char(min_dt + level - 1, 'yyyy-mm-dd') || '</text>'
from const
connect by level <= num_vertical_lines
union all
/* horizontal lines */
select '<line x1="' || to_char(round(left_margin)) || '" x2="' ||
to_char(round(viewbox_width - right_margin)) || '" y1="' ||
to_char(round(top_margin +
(viewbox_height - top_margin - bottom_margin) *
(level - 1) / (num_horizontal_lines - 1))) || '" y2="' ||
to_char(round(top_margin +
(viewbox_height - top_margin - bottom_margin) *
(level - 1) / (num_horizontal_lines - 1))) ||
'" style="stroke:' || const.stroke_horizontal_lines ||
'; stroke-width:' || const.stroke_width_horizontal_lines || '"/>'
from const
connect by level <= num_horizontal_lines
union all
/* values near horizontal lines */
select '<text text-anchor="end" x="' ||
to_char(round(left_margin - x_values_pad)) || '" y="' ||
to_char(round(viewbox_height - bottom_margin -
(viewbox_height - top_margin - bottom_margin) *
(level - 1) / (num_horizontal_lines - 1) +
y_values_pad)) || '" font-size="' || font_size_values ||
'" fill="' || fill_values || '">' ||
to_char(round(max_val / (num_horizontal_lines - 1) * (level - 1), 2)) ||
'</text>'
from const
connect by level <= num_horizontal_lines
union all
/* circles */
select '<circle cx="' || to_char(gd2.x) || '" cy="' || to_char(gd2.y) ||
'" r="' || gd2.radius || '" style="fill:' || const.fill_circles ||
'"/>'
from gd2, const
union all
/* graph data */
select '<line x1="' || to_char(gd2.prev_x) || '" x2="' || to_char(gd2.x) ||
'" y1="' || to_char(gd2.prev_y) || '" y2="' || to_char(gd2.y) ||
'" style="stroke:' || const.stroke_graph || '; stroke-width:' ||
const.stroke_width_graph || '"/>'
from gd2, const
union all
/* footer */
select '</svg>' from dual;
يمكن حفظ نتيجة الاستعلام في ملف بامتداد * .svg وعرضها في المستعرض. إذا رغبت في ذلك ، يمكنك استخدام أي من الأدوات المساعدة لتحويلها إلى تنسيقات رسوم أخرى ، ووضعها على صفحات الويب الخاصة بتطبيقك ، وما إلى ذلك.
والنتيجة هي الصورة التالية:
تطبيق Oracle Metadata Search
تخيل محاولة العثور على شيء ما في التعليمات البرمجية المصدر على Oracle من خلال البحث عن معلومات على عدة خوادم في وقت واحد. يتعلق هذا بالبحث خلال كائنات قاموس بيانات Oracle. مكان العمل للبحث هو واجهة الويب ، حيث يقوم مبرمج المستخدم بإدخال سلسلة البحث وتحديد مربعات الاختيار على خوادم Oracle لإجراء هذا البحث.
محرك بحث الويب قادر على البحث عن صف في كائنات خادم أوراكل في وقت واحد في عدة قواعد بيانات مختلفة للبنك. على سبيل المثال ، يمكنك البحث عن:
- Oracle 61209, ?
- accounts ( .. database link)?
- , , ORA-20001 “ ”?
- IX_CLIENTID - SQL-?
- - ( .. database link) , , , ..?
- - - ? .
- Oracle ? , wm_concat Oracle. .
- - , , ? , Oracle sys_connect_by_path, regexp_instr push_subq.
بناءً على نتائج البحث ، يتم إعطاء المستخدم معلومات حول أي خادم في رمز الوظائف ، والإجراءات ، والحزم ، والمشغلات ، والعروض ، وما إلى ذلك. وجدت النتائج المطلوبة.
دعنا نصف كيف يتم تنفيذ محرك البحث هذا.
جانب العميل ليس معقدًا. تتلقى واجهة الويب سلسلة البحث التي أدخلها المستخدم ، وقائمة الخوادم المراد البحث عنها ، وتسجيل دخول المستخدم. تمررهم صفحة الويب إلى إجراء أوراكل المخزن على خادم المعالج. تاريخ الطلبات إلى محرك البحث ، أي الذي نفذ الطلب الذي تم تسجيله فقط في حالة.
بعد تلقي استعلام بحث ، يقوم جانب الخادم على خادم بحث أوراكل بتنفيذ العديد من الإجراءات في وظائف متوازية تقوم بمسح طرق عرض قاموس البيانات التالية على روابط قاعدة البيانات على خوادم أوراكل المحددة بحثًا عن السلسلة المطلوبة: ، dba_views. كل من الإجراءات ، إذا وجدت شيئًا ما ، يكتب ما تم العثور عليه في جدول نتائج البحث (مع معرف استعلام البحث المقابل).
عند الانتهاء من جميع إجراءات البحث ، يمنح جزء العميل المستخدم كل ما هو مكتوب في جدول نتائج البحث مع معرف استعلام البحث المقابل.
لكن هذا ليس كل شيء. بالإضافة إلى البحث في قاموس بيانات Oracle ، تم أيضًا ربط البحث في مستودع Informatica PowerCenter في الآلية الموضحة. Informatica PowerCenter هي أداة ETL شائعة يستخدمها Sberbank لتحميل معلومات متنوعة في مستودعات البيانات. لدى Informatica PowerCenter بنية مستودع مفتوحة وموثقة جيدًا. في هذا المستودع ، من الممكن البحث عن المعلومات بنفس الطريقة المستخدمة في قاموس بيانات أوراكل. ما هي الجداول والحقول المستخدمة في كود التنزيل الذي تم تطويره باستخدام Informatica PowerCenter؟ ما الذي يمكن العثور عليه في تحويلات المنفذ واستعلامات SQL الصريحة؟ كل هذه المعلومات متوفرة في هياكل المستودع ويمكن العثور عليها. لخبراء PowerCenter ، سأكتب أن محرك البحث الخاص بنا يقوم بمسح مواقع المستودعات التالية بحثًا عن التعيينات أو الجلسات أو سير العمل ،تحتوي على سلسلة البحث في مكان ما: sql override ، سمات mapplet ، المنافذ ، تعريفات المصدر في التعيينات ، تعريفات المصدر ، تعريفات الهدف في التعيينات ، target_definitions ، التعيينات ، mapplets ، سير العمل ، worklets ، الجلسات ، الأوامر ، منافذ التعبير ، مثيلات الجلسة ، حقول تعريف المصدر ، حقول تعريف الهدف ، مهام البريد الإلكتروني.
: , SberProfi DWH/BigData.
SberProfi DWH/BigData , Hadoop, Teradata, Oracle DB, GreenPlum, BI Qlik, SAP BO, Tableau .