Duke ndjekur hapat e Highload++ Siberia 2019 - 8 detyra në Oracle

Привет!

Në datat 24-25 qershor u mbajt në Novosibirsk konferenca Highload++ Siberia 2019. Aty ishin edhe djemtë tanë raporti “Bazat e të dhënave të kontejnerëve të Oracle (CDB/PDB) dhe përdorimi praktik i tyre për zhvillimin e softuerit”, do të postojmë një version tekstual pak më vonë. Ishte e lezetshme, faleminderit olegbunin për organizatën, si dhe për të gjithë ata që erdhën.

Duke ndjekur hapat e Highload++ Siberia 2019 - 8 detyra në Oracle
Në këtë postim, dëshirojmë të ndajmë me ju problemet që kemi pasur në stendën tonë, në mënyrë që të testoni njohuritë tuaja në Oracle. Më poshtë prerjes janë 8 probleme, opsionet e përgjigjeve dhe shpjegimi.

Cila është vlera maksimale e sekuencës që do të shohim si rezultat i ekzekutimit të skriptit të mëposhtëm?

create sequence s start with 1;
 
select s.currval, s.nextval, s.currval, s.nextval, s.currval
from dual
connect by level <= 5;

  • 1
  • 5
  • 10
  • 25
  • Jo, do të ketë një gabim

PërgjigjemSipas dokumentacionit të Oracle (cituar nga 8.1.6):
Brenda një deklarate të vetme SQL, Oracle do të rrisë sekuencën vetëm një herë për rresht. Nëse një deklaratë përmban më shumë se një referencë për NEXTVAL për një sekuencë, Oracle e rrit sekuencën një herë dhe kthen të njëjtën vlerë për të gjitha dukuritë e NEXTVAL. Nëse një deklaratë përmban referenca si për CURRVAL ashtu edhe për NEXTVAL, Oracle rrit sekuencën dhe kthen të njëjtën vlerë si për CURRVAL ashtu edhe për NEXTVAL, pavarësisht renditjes së tyre brenda deklaratës.

Kështu, vlera maksimale do të korrespondojë me numrin e rreshtave, që është 5.

Sa rreshta do të jenë në tabelë si rezultat i ekzekutimit të skriptit të mëposhtëm?

create table t(i integer check (i < 5));
 
create procedure p(p_from integer, p_to integer) as
begin
    for i in p_from .. p_to loop
        insert into t values (i);
    end loop;
end;
/
 
exec p(1, 3);
exec p(4, 6);
exec p(7, 9);

  • 0
  • 3
  • 4
  • 5
  • 6
  • 9

PërgjigjemSipas dokumentacionit të Oracle (cituar nga 11.2):

Përpara ekzekutimit të ndonjë deklarate SQL, Oracle shënon një pikë të nënkuptuar të ruajtjes (jo e disponueshme për ju). Më pas, nëse deklarata dështon, Oracle e kthen atë automatikisht dhe e kthen kodin e gabimit të aplikueshëm në SQLCODE në SQLCA. Për shembull, nëse një deklaratë INSERT shkakton një gabim duke u përpjekur të fusë një vlerë të kopjuar në një indeks unik, deklarata kthehet prapa.

Thirrja e HP nga klienti gjithashtu konsiderohet dhe përpunohet si një deklaratë e vetme. Kështu, thirrja e parë e HP-së përfundon me sukses, pasi ka futur tre regjistrime; thirrja e dytë e HP-së përfundon me një gabim dhe kthen rekordin e katërt që arriti të fuste; thirrja e tretë dështon, dhe ka tre regjistrime në tabelë.

Sa rreshta do të jenë në tabelë si rezultat i ekzekutimit të skriptit të mëposhtëm?

create table t(i integer, constraint i_ch check (i < 3));
 
begin
    insert into t values (1);
    insert into t values (null);
    insert into t values (2);
    insert into t values (null);
    insert into t values (3);
    insert into t values (null);
    insert into t values (4);
    insert into t values (null);
    insert into t values (5);
exception
    when others then
        dbms_output.put_line('Oops!');
end;
/

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

PërgjigjemSipas dokumentacionit të Oracle (cituar nga 11.2):

Një kufizim kontrolli ju lejon të specifikoni një kusht që çdo rresht në tabelë duhet të plotësojë. Për të përmbushur kufizimin, çdo rresht në tabelë duhet ta bëjë kushtin ose TË VËRTETË ose të panjohur (për shkak të një null). Kur Oracle vlerëson një kusht kufizimi kontrolli për një rresht të caktuar, çdo emër kolone në kusht i referohet vlerave të kolonës në atë rresht.

Kështu, vlera null do të kalojë kontrollin dhe blloku anonim do të ekzekutohet me sukses deri në një përpjekje për të futur vlerën 3. Pas kësaj, blloku i trajtimit të gabimit do të fshijë përjashtimin, nuk do të ndodhë asnjë rikthim dhe do të mbeten katër rreshta në tabelë me vlerat 1, null, 2 dhe përsëri null.

Cilat çifte vlerash do të zënë të njëjtën hapësirë ​​në bllok?

create table t (
    a char(1 char),
    b char(10 char),
    c char(100 char),
    i number(4),
    j number(14),
    k number(24),
    x varchar2(1 char),
    y varchar2(10 char),
    z varchar2(100 char));
 
insert into t (a, b, i, j, x, y)
    values ('Y', 'Вася', 10, 10, 'Д', 'Вася');

  • A dhe X
  • B dhe Y
  • C dhe K
  • C dhe Z
  • K dhe Z
  • Unë dhe J
  • J dhe X
  • Të gjitha të listuara

PërgjigjemKëtu janë fragmente nga dokumentacioni (12.1.0.2) për ruajtjen e llojeve të ndryshme të të dhënave në Oracle.

Lloji i të dhënave CHAR
Lloji i të dhënave CHAR specifikon një varg karakteresh me gjatësi fikse në grupin e karaktereve të bazës së të dhënave. Ju specifikoni grupin e karaktereve të bazës së të dhënave kur krijoni bazën tuaj të të dhënave. Oracle siguron që të gjitha vlerat e ruajtura në një kolonë CHAR të kenë gjatësinë e specifikuar sipas madhësisë në semantikën e gjatësisë së zgjedhur. Nëse futni një vlerë që është më e shkurtër se gjatësia e kolonës, atëherë Oracle zbraz vlerën në gjatësinë e kolonës.

Lloji i të dhënave VARCHAR2
Lloji i të dhënave VARCHAR2 specifikon një varg karakteresh me gjatësi të ndryshueshme në grupin e karaktereve të bazës së të dhënave. Ju specifikoni grupin e karaktereve të bazës së të dhënave kur krijoni bazën tuaj të të dhënave. Oracle ruan një vlerë karakteri në një kolonë VARCHAR2 saktësisht siç e specifikoni ju, pa asnjë mbushje bosh, me kusht që vlera të mos e kalojë gjatësinë e kolonës.

Lloji i të dhënave NUMBER
Lloji i të dhënave NUMBER ruan zero, si dhe numra fiks pozitivë dhe negativë me vlera absolute nga 1.0 x 10-130 në por pa përfshirë 1.0 x 10126. Nëse specifikoni një shprehje aritmetike, vlera e së cilës ka një vlerë absolute më të madhe ose të barabartë me 1.0 x 10126, më pas Oracle kthen një gabim. Çdo vlerë NUMRI kërkon nga 1 deri në 22 bajt. Duke marrë parasysh këtë, madhësia e kolonës në bajt për një vlerë të caktuar të të dhënave numerike NUMBER(p), ku p është saktësia e një vlere të caktuar, mund të llogaritet duke përdorur formulën e mëposhtme: ROUND((gjatësia(p)+s)/2))+1 ku s është e barabartë me zero nëse numri është pozitiv, dhe s është i barabartë me 1 nëse numri është negativ.

Përveç kësaj, le të marrim një fragment nga dokumentacioni për ruajtjen e vlerave Null.

Një null është mungesa e një vlere në një kolonë. Nullet tregojnë të dhëna të munguara, të panjohura ose të pazbatueshme. Nullat ruhen në bazën e të dhënave nëse bien midis kolonave me vlera të dhënash. Në këto raste, ata kërkojnë 1 bajt për të ruajtur gjatësinë e kolonës (zero). Nullet pasuese në një rresht nuk kërkojnë ruajtje sepse një kokë e re e rreshtit sinjalizon që kolonat e mbetura në rreshtin e mëparshëm janë të pavlefshme. Për shembull, nëse tre kolonat e fundit të një tabele janë nule, atëherë nuk ruhen të dhëna për këto kolona.

Bazuar në këto të dhëna, ne ndërtojmë arsyetimin. Supozojmë se baza e të dhënave përdor kodimin AL32UTF8. Në këtë kodim, shkronjat ruse do të zënë 2 bajt.

1) A dhe X, vlera e fushës një 'Y' merr 1 bajt, vlera e fushës x 'D' merr 2 bajt
2) B dhe Y, 'Vasya' në b vlera do të mbushet me hapësira deri në 10 karaktere dhe do të marrë 14 bajt, 'Vasya' në d do të marrë 8 byte.
3) C dhe K. Të dyja fushat kanë vlerën NULL, pas tyre ka fusha domethënëse, pra zënë 1 bajt.
4) C dhe Z. Të dyja fushat kanë vlerën NULL, por fusha Z është e fundit në tabelë, kështu që nuk zë hapësirë ​​(0 bajt). Fusha C zë 1 bajt.
5) K dhe Z. Ngjashëm me rastin e mëparshëm. Vlera në fushën K zë 1 bajt, në Z – 0.
6) Unë dhe J. Sipas dokumentacionit, të dyja vlerat do të marrin 2 bajt. Ne llogarisim gjatësinë duke përdorur formulën e marrë nga dokumentacioni: rrumbullakët( (1 + 0)/2) +1 = 1 + 1 = 2.
7) J dhe X. Vlera në fushën J do të marrë 2 bajt, vlera në fushën X do të marrë 2 bajt.

Në total, opsionet e sakta janë: C dhe K, I dhe J, J dhe X.

Sa përafërsisht do të jetë faktori grupues i indeksit T_I?

create table t (i integer);
 
insert into t select rownum from dual connect by level <= 10000;
 
create index t_i on t(i);

  • Rreth dhjetëra
  • Rreth qindra
  • Rreth mijëra
  • Rreth dhjetëra mijëra

PërgjigjemSipas dokumentacionit të Oracle (cituar nga 12.1):

Për një indeks të pemës B, faktori i grupimit të indeksit mat grupimin fizik të rreshtave në lidhje me një vlerë indeksi.

Faktori i grupimit të indeksit ndihmon optimizuesin të vendosë nëse skanimi i indeksit ose skanimi i plotë i tabelës është më efikas për pyetje të caktuara). Një faktor i ulët grupimi tregon një skanim efikas të indeksit.

Një faktor grupimi që është afër numrit të blloqeve në një tabelë tregon se rreshtat janë renditur fizikisht në blloqet e tabelës nga çelësi i indeksit. Nëse baza e të dhënave kryen një skanim të plotë të tabelës, atëherë baza e të dhënave tenton të marrë rreshtat pasi ato ruhen në disk të renditura sipas çelësit të indeksit. Një faktor grupimi që është afër numrit të rreshtave tregon se rreshtat janë të shpërndara rastësisht nëpër blloqet e bazës së të dhënave në lidhje me çelësin e indeksit. Nëse baza e të dhënave kryen një skanim të plotë të tabelës, atëherë baza e të dhënave nuk do të rikthejë rreshtat në asnjë rend të renditur sipas këtij çelësi indeksi.

Në këtë rast, të dhënat janë të renditura në mënyrë ideale, kështu që faktori i grupimit do të jetë i barabartë ose afër me numrin e blloqeve të zëna në tabelë. Për një madhësi standarde blloku prej 8 kilobajt, mund të prisni që rreth një mijë vlera të ngushta të numrave do të futen në një bllok, kështu që numri i blloqeve, dhe si rezultat, faktori i grupimit do të jetë rreth dhjetëra.

Në cilat vlera të N do të ekzekutohet me sukses skripti i mëposhtëm në një bazë të dhënash të rregullt me ​​cilësime standarde?

create table t (
    a varchar2(N char),
    b varchar2(N char),
    c varchar2(N char),
    d varchar2(N char));
 
create index t_i on t (a, b, c, d);

  • 100
  • 200
  • 400
  • 800
  • 1600
  • 3200
  • 6400

PërgjigjemSipas dokumentacionit të Oracle (cituar nga 11.2):

Limitet logjike të bazës së të dhënave

Artikull
Lloji i Limit
Vlera kufitare

Indekset
Madhësia totale e kolonës së indeksuar
75% e madhësisë së bllokut të bazës së të dhënave minus disa shpenzime

Kështu, madhësia totale e kolonave të indeksuara nuk duhet të kalojë 6 Kb. Çfarë ndodh më pas varet nga kodimi bazë i zgjedhur. Për kodimin AL32UTF8, një karakter mund të zërë maksimumi 4 bajt, kështu që në rastin më të keq, 6 kilobajt do të përshtaten rreth 1500 karaktere. Prandaj, Oracle do të ndalojë krijimin e indeksit në N = 400 (kur gjatësia e çelësit në rastin më të keq është 1600 karaktere * 4 bajt + gjatësia e rreshtit), ndërsa në N = 200 (ose më pak) krijimi i indeksit do të funksionojë pa probleme.

Operatori INSERT me aludimin APPEND është krijuar për të ngarkuar të dhënat në modalitetin direkt. Çfarë ndodh nëse aplikohet në tryezën në të cilën varet këmbëza?

  • Të dhënat do të ngarkohen në modalitetin e drejtpërdrejtë, këmbëza do të funksionojë siç pritej
  • Të dhënat do të ngarkohen në modalitetin e drejtpërdrejtë, por këmbëza nuk do të ekzekutohet
  • Të dhënat do të ngarkohen në modalitetin konvencional, këmbëza do të funksionojë ashtu siç duhet
  • Të dhënat do të ngarkohen në modalitetin konvencional, por këmbëza nuk do të ekzekutohet
  • Të dhënat nuk do të ngarkohen, do të regjistrohet një gabim

PërgjigjemNë thelb, kjo është më shumë një çështje logjike. Për të gjetur përgjigjen e saktë, unë do të sugjeroja modelin e mëposhtëm të arsyetimit:

  1. Futja në modalitetin e drejtpërdrejtë kryhet me formimin e drejtpërdrejtë të një blloku të dhënash, duke anashkaluar motorin SQL, i cili siguron shpejtësi të lartë. Kështu, sigurimi i ekzekutimit të këmbëzës është shumë i vështirë, nëse jo i pamundur, dhe nuk ka asnjë pikë në këtë, pasi prapë do të ngadalësojë rrënjësisht futjen.
  2. Dështimi për të ekzekutuar këmbëzën do të çojë në faktin se, nëse të dhënat në tabelë janë të njëjta, gjendja e bazës së të dhënave në tërësi (tabelat e tjera) do të varet nga mënyra në të cilën janë futur këto të dhëna. Kjo padyshim do të shkatërrojë integritetin e të dhënave dhe nuk mund të aplikohet si zgjidhje në prodhim.
  3. Pamundësia për të kryer operacionin e kërkuar përgjithësisht trajtohet si një gabim. Por këtu duhet të kujtojmë se APPEND është një aluzion, dhe logjika e përgjithshme e aludimeve është se ato merren parasysh nëse është e mundur, por nëse jo, operatori ekzekutohet pa marrë parasysh aludimin.

Pra përgjigja e pritshme është të dhënat do të ngarkohen në modalitetin normal (SQL), këmbëza do të ndizet.

Sipas dokumentacionit të Oracle (cituar nga 8.04):

Shkeljet e kufizimeve do të bëjnë që deklarata të ekzekutohet në mënyrë serike, duke përdorur shtegun konvencional të futjes, pa paralajmërime ose mesazhe gabimi. Një përjashtim është kufizimi i deklaratave që hyjnë në të njëjtën tabelë më shumë se një herë në një transaksion, gjë që mund të shkaktojë mesazhe gabimi.
Për shembull, nëse aktivizuesit ose integriteti i referencës janë të pranishëm në tabelë, atëherë sugjerimi APPEND do të shpërfillet kur përpiqeni të përdorni INSERT me ngarkesë të drejtpërdrejtë (serial ose paralel), si dhe sugjerimin ose klauzolën PARALLEL, nëse ka.

Çfarë do të ndodhë kur të ekzekutohet skripti i mëposhtëm?

create table t(i integer not null primary key, j integer references t);
 
create trigger t_a_i after insert on t for each row
declare
    pragma autonomous_transaction;
begin
    insert into t values (:new.i + 1, :new.i);
    commit;
end;
/
 
insert into t values (1, null);

  • Ekzekutim i suksesshëm
  • Dështim për shkak të gabimit sintaksor
  • Gabim: Transaksioni autonom nuk është i vlefshëm
  • Gabim në lidhje me tejkalimin e maksimumit të vendosjes së thirrjeve
  • Gabim në shkeljen e çelësit të huaj
  • Gabim në lidhje me bravat

PërgjigjemTabela dhe këmbëza janë krijuar mjaft saktë dhe ky operacion nuk duhet të çojë në probleme. Lejohen gjithashtu transaksione autonome në një shkas, përndryshe regjistrimi nuk do të ishte i mundur, për shembull.

Pas futjes së rreshtit të parë, një shkrepje e suksesshme e këmbëzës do të shkaktonte futjen e rreshtit të dytë, duke shkaktuar ndezjen përsëri të këmbëzës, futjen e një rreshti të tretë, e kështu me radhë derisa deklarata dështoi për shkak të tejkalimit të foleve maksimale të thirrjeve. Megjithatë, një tjetër pikë delikate hyn në lojë. Në kohën kur ekzekutohet këmbëza, commit nuk ka përfunduar ende për rekordin e parë të futur. Prandaj, një nxitës që funksionon në një transaksion autonom përpiqet të fusë në tabelë një rresht që i referohet një çelësi të huaj një rekord që ende nuk është kryer. Kjo rezulton në një pritje (transaksioni autonom pret që transaksioni kryesor të angazhohet për të parë nëse mund të futë të dhëna) dhe në të njëjtën kohë transaksioni kryesor pret që transaksioni autonom të vazhdojë të funksionojë pas aktivizimit. Ndodh një bllokim dhe, si rezultat, transaksioni autonom anulohet për arsye që lidhen me bllokimet.

Vetëm përdoruesit e regjistruar mund të marrin pjesë në anketë. Hyni, te lutem

Ishte e vështirë të?

  • Si dy gishta, menjëherë vendosa gjithçka saktë.

  • Jo me të vërtetë, gabova për disa pyetje.

  • Gjysmën e zgjidha saktë.

  • E mora me mend përgjigjen dy herë!

  • Unë do të shkruaj në komente

14 përdorues votuan. 10 përdorues abstenuan.

Burimi: www.habr.com

Shto një koment