Sekojot Highload++ Siberia 2019 pēdām ā€” 8 uzdevumi pakalpojumā Oracle

Hi!

24.-25.jÅ«nijā Novosibirskā notika konference Highload++ Siberia 2019. Tur bija arÄ« mÅ«su puiÅ”i. Ziņot ā€œOracle konteineru datu bāzes (CDB/PDB) un to praktiskā izmantoÅ”ana programmatÅ«ras izstrādēā€, teksta versiju publicēsim nedaudz vēlāk. Bija forÅ”i, paldies olegbunÄ«ns organizācijai, kā arÄ« visiem, kas ieradās.

Sekojot Highload++ Siberia 2019 pēdām ā€” 8 uzdevumi pakalpojumā Oracle
Å ajā ierakstā mēs vēlamies dalÄ«ties ar jums problēmām, kas radās mÅ«su stendā, lai jÅ«s varētu pārbaudÄ«t savas Oracle zināŔanas. Zem griezuma ir 8 problēmas, atbilžu varianti un skaidrojums.

Kāda ir maksimālā secÄ«bas vērtÄ«ba, ko mēs redzēsim, izpildot Ŕādu skriptu?

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
  • Nē, bÅ«s kļūda

atbildeSaskaņā ar Oracle dokumentāciju (citēts no 8.1.6.):
Viena SQL priekÅ”raksta ietvaros Oracle palielinās secÄ«bu tikai vienu reizi rindā. Ja priekÅ”raksts satur vairākas atsauces uz NEXTVAL secÄ«bai, Oracle palielina secÄ«bu vienu reizi un atgriež vienu un to paÅ”u vērtÄ«bu visiem NEXTVAL gadÄ«jumiem. Ja priekÅ”rakstā ir atsauces gan uz CURRVAL, gan uz NEXTVAL, Oracle palielina secÄ«bu un atgriež vienu un to paÅ”u vērtÄ«bu gan CURRVAL, gan NEXTVAL neatkarÄ«gi no to secÄ«bas priekÅ”rakstā.

Tātad, maksimālā vērtība atbildīs rindu skaitam, tas ir, 5.

Cik rindu būs tabulā, izpildot Ŕādu skriptu?

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

atbildeSaskaņā ar Oracle dokumentāciju (citēts no 11.2.):

Pirms jebkura SQL priekÅ”raksta izpildes Oracle atzÄ«mē netieÅ”u saglabāŔanas punktu (jums nav pieejams). Pēc tam, ja priekÅ”raksts neizdodas, Oracle to automātiski atgriež un SQLCA atgriež piemērojamo kļūdas kodu SQLCODE. Piemēram, ja INSERT priekÅ”raksts izraisa kļūdu, mēģinot ievietot dublikātu unikālā rādÄ«tājā, priekÅ”raksts tiek atcelts.

ArÄ« klienta zvanÄ«Å”ana HP tiek uzskatÄ«ta un apstrādāta kā viens paziņojums. Tādējādi pirmais HP izsaukums tiek veiksmÄ«gi pabeigts, ievietojot trÄ«s ierakstus; otrais HP izsaukums beidzas ar kļūdu un atgriež ceturto ierakstu, ko izdevās ievietot; treÅ”ais zvans neizdodas, un tabulā ir trÄ«s ieraksti.

Cik rindu būs tabulā, izpildot Ŕādu skriptu?

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

atbildeSaskaņā ar Oracle dokumentāciju (citēts no 11.2.):

Pārbaudes ierobežojums ļauj norādÄ«t nosacÄ«jumu, kas jāatbilst katrai tabulas rindai. Lai izpildÄ«tu ierobežojumu, katrai tabulas rindai nosacÄ«jumam ir jābÅ«t TRUE vai nezināmam (nulles dēļ). Kad Oracle novērtē pārbaudes ierobežojuma nosacÄ«jumu konkrētai rindai, visi nosacÄ«juma kolonnu nosaukumi attiecas uz kolonnu vērtÄ«bām Å”ajā rindā.

Tādējādi vērtÄ«ba null izturēs pārbaudi, un anonÄ«mais bloks tiks veiksmÄ«gi izpildÄ«ts lÄ«dz mēģinājumam ievietot vērtÄ«bu 3. Pēc tam kļūdu apstrādes bloks nodzēsÄ«s izņēmumu, netiks veikta atcelÅ”ana un tabulā bÅ«s palikuÅ”as četras rindas ar vērtÄ«bām 1, null, 2 un vēlreiz nulle.

Kuri vērtību pāri blokā aizņems tikpat daudz vietas?

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 un X
  • B un Y
  • C un K
  • C un Z
  • K un Z
  • Es un Dž
  • J un X
  • Visi uzskaitÄ«ti

atbildeŠeit ir izvilkumi no dokumentācijas (12.1.0.2) par dažāda veida datu glabāŔanu Oracle.

CHAR datu tips
CHAR datu tips nosaka noteikta garuma rakstzÄ«mju virkni datu bāzes rakstzÄ«mju kopā. Veidojot datu bāzi, jÅ«s norādāt datu bāzes rakstzÄ«mju kopu. Oracle nodroÅ”ina, ka visām CHAR kolonnā saglabātajām vērtÄ«bām ir garums, kas norādÄ«ts pēc izmēra atlasÄ«tajā garuma semantikā. Ja ievietojat vērtÄ«bu, kas ir Ä«sāka par kolonnas garumu, Oracle vērtÄ«bu pielāgo kolonnas garumam.

VARCHAR2 datu tips
Datu tips VARCHAR2 nosaka mainÄ«ga garuma rakstzÄ«mju virkni datu bāzes rakstzÄ«mju kopā. Veidojot datu bāzi, jÅ«s norādāt datu bāzes rakstzÄ«mju kopu. Oracle saglabā rakstzÄ«mes vērtÄ«bu kolonnā VARCHAR2 tieÅ”i tā, kā to norādāt, bez tukÅ”as aizpildÄ«Å”anas, ja vērtÄ«ba nepārsniedz kolonnas garumu.

NUMBER datu tips
Datu tips NUMBER saglabā nulles, kā arÄ« pozitÄ«vus un negatÄ«vus fiksētus skaitļus ar absolÅ«tajām vērtÄ«bām no 1.0 x 10-130 lÄ«dz 1.0 x 10126, bet neieskaitot. Ja norādāt aritmētisko izteiksmi, kuras absolÅ«tā vērtÄ«ba ir lielāka vai vienāda ar 1.0 x 10126, tad Oracle atgriež kļūdu. Katrai NUMBER vērtÄ«bai ir nepiecieÅ”ami 1ā€“22 baiti. Ņemot to vērā, kolonnas lielumu baitos konkrētai skaitlisko datu vērtÄ«bai NUMBER(p), kur p ir dotās vērtÄ«bas precizitāte, var aprēķināt, izmantojot Ŕādu formulu: APKĀRTS((garums(p)+s)/2))+1 kur s ir vienāds ar nulli, ja skaitlis ir pozitÄ«vs, un s ir vienāds ar 1, ja skaitlis ir negatÄ«vs.

Turklāt ņemsim fragmentu no dokumentācijas par Null vērtÄ«bu saglabāŔanu.

Nulle ir vērtÄ«bas neesamÄ«ba kolonnā. Nulles norāda trÅ«kstoÅ”us, nezināmus vai nepiemērojamus datus. Nulles tiek saglabātas datu bāzē, ja tās atrodas starp kolonnām ar datu vērtÄ«bām. Šādos gadÄ«jumos kolonnas garuma (nulles) glabāŔanai ir nepiecieÅ”ams 1 baits. Rindas beigu nullēm nav nepiecieÅ”ama krātuve, jo jauna rindas galvene norāda, ka pārējās kolonnas iepriekŔējā rindā ir nulles. Piemēram, ja tabulas pēdējās trÄ«s kolonnas ir nulles, par Ŕīm kolonnām netiek glabāti dati.

Pamatojoties uz Å”iem datiem, mēs veidojam argumentāciju. Mēs pieņemam, ka datu bāze izmanto AL32UTF8 kodējumu. Å ajā kodējumā krievu burti aizņems 2 baitus.

1) A un X, lauka a vērtÄ«ba ā€œYā€ aizņem 1 baitu, lauka x vērtÄ«ba ā€œDā€ aizņem 2 baitus.
2) B un Y ā€” b vērtÄ«ba tiks papildināta ar atstarpēm lÄ«dz 10 rakstzÄ«mēm, un tā aizņems 14 baitus, bet vērtÄ«ba ā€œVasyaā€ laukā d aizņems 8 baitus.
3) C un K. Abiem laukiem ir vērtība NULL, aiz tiem ir nozīmīgi lauki, tāpēc tie aizņem 1 baitu.
4) C un Z. Abiem laukiem ir vērtība NULL, bet lauks Z ir pēdējais tabulā, tāpēc tas neaizņem vietu (0 baiti). Lauks C aizņem 1 baitu.
5) K un Z. LÄ«dzÄ«gi kā iepriekŔējā gadÄ«jumā. VērtÄ«ba laukā K aizņem 1 baitu, laukā Z ā€“ 0.
6) I un J. Saskaņā ar dokumentāciju abām vērtībām būs 2 baiti. Mēs aprēķinām garumu, izmantojot formulu, kas ņemta no dokumentācijas: apaļa( (1 + 0)/2) +1 = 1 + 1 = 2.
7) J un X. Vērtība laukā J aizņems 2 baitus, vērtība laukā X aizņems 2 baitus.

Kopumā pareizās iespējas ir: C un K, I un J, J un X.

Kāds aptuveni būs T_I indeksa klasterizācijas faktors?

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

  • Apmēram desmitiem
  • Apmēram simtiem
  • Apmēram tÅ«kstoÅ”iem
  • Apmēram desmitiem tÅ«kstoÅ”u

atbildeSaskaņā ar Oracle dokumentāciju (citēts no 12.1.):

B-koka indeksam indeksa klasterizācijas faktors mēra rindu fizisko grupÄ“Å”anu attiecÄ«bā pret indeksa vērtÄ«bu.

Indeksa klasterizācijas faktors palÄ«dz optimizētājam izlemt, vai indeksa skenÄ“Å”ana vai pilnas tabulas skenÄ“Å”ana ir efektÄ«vāka noteiktiem vaicājumiem). Zems klasterizācijas koeficients norāda uz efektÄ«vu indeksa skenÄ“Å”anu.

Klasterizācijas faktors, kas ir tuvu bloku skaitam tabulā, norāda, ka rindas tabulas blokos ir fiziski sakārtotas pēc indeksa atslēgas. Ja datu bāze veic pilnu tabulas skenÄ“Å”anu, datu bāzei ir tendence izgÅ«t rindas, jo tās tiek glabātas diskā, sakārtotas pēc indeksa atslēgas. Klasterizācijas faktors, kas ir tuvu rindu skaitam, norāda, ka rindas ir nejauÅ”i izkliedētas pa datu bāzes blokiem saistÄ«bā ar indeksa atslēgu. Ja datu bāze veic pilnu tabulas skenÄ“Å”anu, datu bāze neizgÅ«s rindas nevienā sakārtotā secÄ«bā pēc Ŕīs indeksa atslēgas.

Å ajā gadÄ«jumā dati ir ideāli sakārtoti, tāpēc klasterizācijas koeficients bÅ«s vienāds ar aizņemto bloku skaitu tabulā vai tuvu tam. Standarta bloka lielumam 8 kilobaiti var sagaidÄ«t, ka vienā blokā ietilps aptuveni tÅ«kstotis Å”auru skaitļu vērtÄ«bu, tāpēc bloku skaits un rezultātā klasterizācijas koeficients bÅ«s apmēram desmitiem.

Ar kādām N vērtÄ«bām parastajā datu bāzē ar standarta iestatÄ«jumiem tiks veiksmÄ«gi izpildÄ«ts Ŕāds skripts?

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

atbildeSaskaņā ar Oracle dokumentāciju (citēts no 11.2.):

Loģiskās datu bāzes ierobežojumi

Punkts
Limita veids
Robežvērtība

Indeksi
Kopējais indeksētās kolonnas lielums
75% no datu bāzes bloka lieluma, atskaitot dažas pieskaitāmās izmaksas

Tādējādi kopējais indeksēto kolonnu lielums nedrÄ«kst pārsniegt 6 Kb. Tālākais ir atkarÄ«gs no izvēlētā bāzes kodējuma. AL32UTF8 kodējumam viena rakstzÄ«me var aizņemt ne vairāk kā 4 baitus, tāpēc sliktākajā gadÄ«jumā aptuveni 6 rakstzÄ«mes ietilps 1500 kilobaitos. Tāpēc Oracle neļaus indeksa izveidi pie N = 400 (ja sliktākā gadÄ«juma atslēgas garums ir 1600 rakstzÄ«mes * 4 baiti + rindas garums), savukārt pie N = 200 (vai mazāk) indeksa izveide darbosies bez problēmām.

INSERT operators ar APPEND mājienu ir paredzēts datu ielādei tieÅ”ajā režīmā. Kas notiek, ja tas tiek piemērots galdam, uz kura karājas sprÅ«da?

  • Dati tiks ielādēti tieÅ”ajā režīmā, trigeris darbosies kā paredzēts
  • Dati tiks ielādēti tieÅ”ajā režīmā, bet trigeris netiks izpildÄ«ts
  • Dati tiks ielādēti parastajā režīmā, sprÅ«da darbosies kā nākas
  • Dati tiks ielādēti parastajā režīmā, bet trigeris netiks izpildÄ«ts
  • Dati netiks ielādēti, tiks ierakstÄ«ta kļūda

atbildeBūtībā tas vairāk ir loģikas jautājums. Lai atrastu pareizo atbildi, es ieteiktu Ŕādu argumentācijas modeli:

  1. IevietoÅ”ana tieÅ”ajā režīmā tiek veikta, tieÅ”i veidojot datu bloku, apejot SQL dzinēju, kas nodroÅ”ina lielu ātrumu. Tādējādi sprÅ«da izpildes nodroÅ”ināŔana ir ļoti sarežģīta, ja ne neiespējama, un tam nav jēgas, jo tas joprojām radikāli palēninās ievietoÅ”anu.
  2. Ja netiek izpildīts trigeris, tad, ja dati tabulā ir vienādi, datu bāzes stāvoklis kopumā (citas tabulas) būs atkarīgs no režīma, kurā Ŕie dati tika ievietoti. Tas acīmredzami iznīcinās datu integritāti, un to nevar izmantot kā risinājumu ražoŔanā.
  3. Nespēja veikt pieprasÄ«to darbÄ«bu parasti tiek uzskatÄ«ta par kļūdu. Bet Å”eit jāatceras, ka APPEND ir mājiens, un vispārÄ«gā mājienu loÄ£ika ir tāda, ka, ja iespējams, tie tiek ņemti vērā, bet, ja nē, tad operators tiek izpildÄ«ts, neņemot vērā mājienu.

Tātad gaidāmā atbilde ir dati tiks ielādēti normālā (SQL) režīmā, trigeris tiks aktivizēts.

Saskaņā ar Oracle dokumentāciju (citēts no 8.04.):

Ierobežojumu pārkāpumi izraisÄ«s priekÅ”raksta izpildi sērijveidā, izmantojot parasto ievietoÅ”anas ceļu, bez brÄ«dinājumiem vai kļūdu ziņojumiem. Izņēmums ir aizliegums paziņojumiem piekļūt vienai un tai paÅ”ai tabulai vairāk nekā vienu reizi darÄ«juma laikā, kas var izraisÄ«t kļūdu ziņojumus.
Piemēram, ja tabulā ir trigeri vai atsauces integritāte, tad APPEND padoms tiks ignorēts, mēģinot izmantot tieŔās ielādes INSERT (seriālo vai paralēlo), kā arÄ« PARALĒLU mājienu vai klauzulu, ja tāds ir.

Kas notiks, kad tiks izpildīts Ŕāds skripts?

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);

  • VeiksmÄ«ga pabeigÅ”ana
  • Kļūme sintakses kļūdas dēļ
  • Kļūda: autonomais darÄ«jums nav derÄ«gs
  • Kļūda, kas saistÄ«ta ar maksimālā zvanu ligzdoÅ”anas apjoma pārsniegÅ”anu
  • Ārējās atslēgas pārkāpuma kļūda
  • Kļūda, kas saistÄ«ta ar slēdzenēm

atbildeTabula un sprÅ«da ir izveidoti diezgan pareizi, un Å”ai darbÄ«bai nevajadzētu radÄ«t problēmas. Ir atļautas arÄ« autonomas transakcijas trigerā, pretējā gadÄ«jumā, piemēram, reÄ£istrÄ“Å”ana nebÅ«tu iespējama.

Pēc pirmās rindas ievietoÅ”anas veiksmÄ«ga aktivizētāja aktivizÄ“Å”ana izraisÄ«tu otrās rindas ievietoÅ”anu, izraisot aktivizētāja atkārtotu aktivizÄ“Å”anu, treŔās rindas ievietoÅ”anu un tā tālāk, lÄ«dz paziņojums neizdevās, jo tika pārsniegts maksimālais izsaukumu ligzdoÅ”anas skaits. Tomēr spēlē vēl viens smalks punkts. Laikā, kad tiek izpildÄ«ts trigeris, pirmā ievietotā ieraksta apņemÅ”anās vēl nav pabeigta. Tāpēc trigeris, kas darbojas autonomā darÄ«jumā, mēģina ievietot tabulā rindu, kas atsaucas uz ārējo atslēgu uz ierakstu, kas vēl nav veikts. Tā rezultātā notiek gaidÄ«Å”ana (autonomais darÄ«jums gaida, lÄ«dz galvenais darÄ«jums uzņemsies saistÄ«bas, lai redzētu, vai tas var ievietot datus), un tajā paŔā laikā galvenais darÄ«jums gaida, lÄ«dz autonomais darÄ«jums turpinās darboties pēc trigera. Notiek strupceļŔ, kā rezultātā autonomais darÄ«jums tiek atcelts ar slēdzenēm saistÄ«tu iemeslu dēļ.

Aptaujā var piedalīties tikai reģistrēti lietotāji. Ielogoties, lūdzu.

Bija grūti?

  • Kā ar diviem pirkstiem uzreiz visu izlēmu pareizi.

  • Nav Ä«sti, es kļūdÄ«jos pāris jautājumos.

  • Pusi no tā atrisināju pareizi.

  • Es divreiz uzminēju atbildi!

  • RakstÄ«Å”u komentāros

Nobalsoja 14 lietotāji. 10 lietotāji atturējās.

Avots: www.habr.com

Pievieno komentāru