Följer i fotspåren av Highload++ Siberia 2019 - 8 uppgifter på Oracle

Hälsningar!

Den 24-25 juni hölls konferensen Highload++ Siberia 2019 i Novosibirsk. Våra killar var också där Rapportera "Oracle containerdatabaser (CDB/PDB) och deras praktiska användning för mjukvaruutveckling", vi kommer att publicera en textversion lite senare. Det var coolt, tack olegbunin för organisationen, såväl som för alla som kom.

Följer i fotspåren av Highload++ Siberia 2019 - 8 uppgifter på Oracle
I det här inlägget vill vi dela med dig av problemen som vi hade i vår monter så att du kan testa dina Oracle-kunskaper. Under snittet finns 8 problem, svarsalternativ och förklaring.

Vilket är det maximala sekvensvärdet vi kommer att se som ett resultat av att köra följande skript?

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
  • Nej, det blir ett fel

SvarEnligt Oracle-dokumentationen (citerad från 8.1.6):
Inom en enda SQL-sats kommer Oracle att öka sekvensen endast en gång per rad. Om en sats innehåller mer än en referens till NEXTVAL för en sekvens, ökar Oracle sekvensen en gång och returnerar samma värde för alla förekomster av NEXTVAL. Om en sats innehåller referenser till både CURRVAL och NEXTVAL, ökar Oracle sekvensen och returnerar samma värde för både CURRVAL och NEXTVAL oavsett deras ordning i satsen.

Sålunda det maximala värdet kommer att motsvara antalet rader, det vill säga 5.

Hur många rader kommer att finnas i tabellen som ett resultat av att köra följande skript?

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

SvarEnligt Oracle-dokumentationen (citerad från 11.2):

Innan någon SQL-sats körs, markerar Oracle en implicit räddningspunkt (inte tillgänglig för dig). Sedan, om satsen misslyckas, återställer Oracle den automatiskt och returnerar den tillämpliga felkoden till SQLCODE i SQLCA. Till exempel, om en INSERT-sats orsakar ett fel genom att försöka infoga ett dubblettvärde i ett unikt index, rullas satsen tillbaka.

Att ringa HP från klienten betraktas och behandlas också som ett enda uttalande. Således slutförs det första HP-samtalet framgångsrikt efter att ha infogat tre poster; det andra HP-anropet slutar med ett fel och rullar tillbaka den fjärde posten som den lyckades infoga; det tredje samtalet misslyckas, och det finns tre poster i tabellen.

Hur många rader kommer att finnas i tabellen som ett resultat av att köra följande skript?

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

SvarEnligt Oracle-dokumentationen (citerad från 11.2):

En kontrollbegränsning låter dig ange ett villkor som varje rad i tabellen måste uppfylla. För att uppfylla begränsningen måste varje rad i tabellen göra villkoret antingen TRUE eller okänt (på grund av en noll). När Oracle utvärderar ett kontrollvillkor för en viss rad, refererar eventuella kolumnnamn i villkoret till kolumnvärdena i den raden.

Således kommer värdet null att passera kontrollen, och det anonyma blocket kommer att exekveras framgångsrikt tills ett försök att infoga värdet 3. Efter detta kommer felhanteringsblocket att ta bort undantaget, ingen rollback kommer att ske, och det kommer att finnas fyra rader kvar i tabellen med värden 1, null, 2 och null igen.

Vilka värdepar kommer att ta upp lika mycket utrymme i blocket?

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 och X
  • B och Y
  • C och K
  • C och Z
  • K och Z
  • Jag och J
  • J och X
  • Alla listade

SvarHär är utdrag ur dokumentationen (12.1.0.2) om lagring av olika typer av data i Oracle.

CHAR Datatyp
CHAR-datatypen anger en teckensträng med fast längd i databasens teckenuppsättning. Du anger databasteckenuppsättningen när du skapar din databas. Oracle säkerställer att alla värden som lagras i en CHAR-kolumn har den längd som anges av storlek i den valda längdsemantiken. Om du infogar ett värde som är kortare än kolumnlängden, så fyller Oracle blankt på värdet till kolumnlängden.

VARCHAR2 Datatyp
Datatypen VARCHAR2 anger en teckensträng med variabel längd i databasens teckenuppsättning. Du anger databasteckenuppsättningen när du skapar din databas. Oracle lagrar ett teckenvärde i en VARCHAR2-kolumn precis som du anger det, utan någon blank utfyllnad, förutsatt att värdet inte överstiger kolumnens längd.

NUMBER Datatyp
Datatypen NUMBER lagrar noll såväl som positiva och negativa fasta tal med absoluta värden från 1.0 x 10-130 till men inte inklusive 1.0 x 10126. Om du anger ett aritmetiskt uttryck vars värde har ett absolutvärde som är större än eller lika med 1.0 x 10126, sedan returnerar Oracle ett fel. Varje NUMBER-värde kräver från 1 till 22 byte. Med hänsyn till detta kan kolumnstorleken i byte för ett visst numeriskt datavärde NUMBER(p), där p är precisionen för ett givet värde, beräknas med följande formel: RUND((längd(p)+s)/2))+1 där s är lika med noll om talet är positivt och s är lika med 1 om talet är negativt.

Låt oss dessutom ta ett utdrag ur dokumentationen om att lagra nollvärden.

En noll är frånvaron av ett värde i en kolumn. Nollor indikerar saknade, okända eller otillämpliga data. Nollor lagras i databasen om de hamnar mellan kolumner med datavärden. I dessa fall kräver de 1 byte för att lagra längden på kolumnen (noll). Efterföljande nollor i en rad kräver ingen lagring eftersom en ny radrubrik signalerar att de återstående kolumnerna i föregående rad är null. Till exempel, om de tre sista kolumnerna i en tabell är null, lagras ingen data för dessa kolumner.

Baserat på dessa data bygger vi resonemang. Vi antar att databasen använder AL32UTF8-kodning. I denna kodning kommer ryska bokstäver att uppta 2 byte.

1) A och X, värdet på fält a 'Y' tar 1 byte, värdet på fält x 'D' tar 2 byte
2) B och Y, 'Vasya' i b värdet kommer att fyllas med mellanslag upp till 10 tecken och kommer att ta 14 byte, 'Vasya' i d kommer att ta 8 byte.
3) C och K. Båda fälten har värdet NULL, efter dem finns betydande fält, så de upptar 1 byte.
4) C och Z. Båda fälten har värdet NULL, men fält Z är det sista i tabellen, så det tar inte upp plats (0 byte). Fält C upptar 1 byte.
5) K och Z. Liknar föregående fall. Värdet i K-fältet upptar 1 byte, i Z – 0.
6) I och J. Enligt dokumentationen kommer båda värdena att ta 2 byte. Vi beräknar längden med hjälp av formeln hämtad från dokumentationen: round( (1 + 0)/2) +1 = 1 + 1 = 2.
7) J och X. Värdet i J-fältet tar 2 byte, värdet i X-fältet tar 2 byte.

Totalt är de korrekta alternativen: C och K, I och J, J och X.

Ungefär vad blir klustringsfaktorn för T_I-indexet?

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

  • Om tiotals
  • Om hundratals
  • Om tusentals
  • Cirka tiotusentals

SvarEnligt Oracle-dokumentationen (citerad från 12.1):

För ett B-trädindex mäter indexklustringsfaktorn den fysiska grupperingen av rader i förhållande till ett indexvärde.

Indexklustringsfaktorn hjälper optimeraren att avgöra om en indexskanning eller en fullständig tabellsökning är mer effektiv för vissa frågor). En låg klustringsfaktor indikerar en effektiv indexskanning.

En klustringsfaktor som är nära antalet block i en tabell indikerar att raderna är fysiskt ordnade i tabellblocken av indexnyckeln. Om databasen utför en fullständig tabellsökning, tenderar databasen att hämta raderna eftersom de lagras på disken sorterade efter indexnyckeln. En klustringsfaktor som ligger nära antalet rader indikerar att raderna är slumpmässigt utspridda över databasblocken i förhållande till indexnyckeln. Om databasen utför en fullständig tabellsökning, kommer databasen inte att hämta rader i någon sorterad ordning efter denna indexnyckel.

I det här fallet sorteras data idealiskt, så klustringsfaktorn kommer att vara lika med eller nära antalet upptagna block i tabellen. För en standardblockstorlek på 8 kilobyte kan du förvänta dig att cirka tusen smala talvärden kommer att passa in i ett block, så antalet block och som ett resultat kommer klustringsfaktorn att vara ungefär tiotal.

Vid vilka värden på N kommer följande skript att köras framgångsrikt i en vanlig databas med standardinställningar?

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

SvarEnligt Oracle-dokumentationen (citerad från 11.2):

Logiska databasgränser

Artikel
Typ av gräns
Gränsvärde

Index
Total storlek på indexerad kolumn
75 % av databasblockets storlek minus viss overhead

Den totala storleken på indexerade kolumner bör därför inte överstiga 6Kb. Vad som händer sedan beror på den valda baskodningen. För AL32UTF8-kodning kan ett tecken uppta maximalt 4 byte, så i värsta fall kommer cirka 6 tecken att passa in i 1500 kilobyte. Därför kommer Oracle inte tillåta indexskapande vid N = 400 (när nyckellängden i värsta fall är 1600 tecken * 4 byte + radlängd), medan vid N = 200 (eller mindre) att skapa indexet fungerar utan problem.

INSERT-operatorn med APPEND-tipset är utformad för att ladda data i direktläge. Vad händer om det appliceras på bordet som avtryckaren hänger på?

  • Data kommer att laddas i direktläge, triggern kommer att fungera som förväntat
  • Data kommer att laddas i direktläge, men triggern kommer inte att exekveras
  • Data kommer att laddas i konventionellt läge, triggern kommer att fungera som den ska
  • Data kommer att laddas i konventionellt läge, men triggern kommer inte att exekveras
  • Data kommer inte att laddas, ett fel kommer att registreras

SvarI grund och botten är detta mer en fråga om logik. För att hitta rätt svar skulle jag föreslå följande resonemangsmodell:

  1. Infogning i direktläge utförs genom direkt bildning av ett datablock, förbi SQL-motorn, vilket säkerställer hög hastighet. Därför är det mycket svårt, för att inte säga omöjligt att säkerställa utförandet av utlösaren, och det är ingen mening med detta, eftersom det fortfarande radikalt kommer att bromsa insättningen.
  2. Underlåtenhet att exekvera triggern kommer att leda till att om data i tabellen är densamma, kommer tillståndet för databasen som helhet (andra tabeller) att bero på i vilket läge dessa data infogades. Detta kommer uppenbarligen att förstöra dataintegriteten och kan inte användas som en lösning i produktionen.
  3. Oförmågan att utföra den begärda operationen behandlas i allmänhet som ett fel. Men här bör vi komma ihåg att APPEND är en ledtråd, och den allmänna logiken för tips är att de tas med i beräkningen om möjligt, men om inte, exekveras operatören utan att ta hänsyn till tipset.

Så det förväntade svaret är data kommer att laddas i normalt (SQL) läge, utlösaren aktiveras.

Enligt Oracle-dokumentationen (citerad från 8.04):

Brott mot begränsningarna kommer att göra att satsen körs seriellt, med hjälp av den konventionella infogningssökvägen, utan varningar eller felmeddelanden. Ett undantag är begränsningen för att uttalanden får åtkomst till samma tabell mer än en gång i en transaktion, vilket kan orsaka felmeddelanden.
Till exempel, om triggers eller referensintegritet finns på bordet, kommer APPEND-tipset att ignoreras när du försöker använda INSERT med direkt belastning (seriell eller parallell), såväl som PARALLEL-tipset eller klausulen, om någon.

Vad händer när följande skript körs?

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

  • Lyckad avrättning
  • Fel på grund av syntaxfel
  • Fel: Autonom transaktion är inte giltig
  • Fel relaterat till överskridandet av den maximala anropskapslingen
  • Fel på utländsk nyckel
  • Fel relaterat till lås

SvarTabellen och triggern skapas helt korrekt och denna operation bör inte leda till problem. Autonoma transaktioner i en trigger är också tillåtna, annars skulle till exempel loggning inte vara möjlig.

Efter att ha infogat den första raden, skulle en framgångsrik triggeravfyrning göra att den andra raden infogas, vilket gör att avtryckaren avfyras igen, infogning av en tredje rad, och så vidare tills satsen misslyckades på grund av att den maximala kapslingen av samtal överskrids. Men en annan subtil punkt spelar in. Vid den tidpunkt då triggern exekveras har commit ännu inte slutförts för den första infogade posten. Därför försöker en utlösare som körs i en autonom transaktion att infoga en rad i tabellen som refererar till en främmande nyckel till en post som ännu inte har registrerats. Detta resulterar i en väntan (den autonoma transaktionen väntar på att huvudtransaktionen commit för att se om den kan infoga data) och samtidigt väntar huvudtransaktionen på att den autonoma transaktionen ska fortsätta fungera efter triggern. Ett dödläge uppstår och som ett resultat avbryts den autonoma transaktionen på grund av skäl relaterade till lås.

Endast registrerade användare kan delta i undersökningen. Logga in, Snälla du.

var det svårt att?

  • Som två fingrar bestämde jag omedelbart allt korrekt.

  • Inte riktigt, jag hade fel på ett par frågor.

  • Jag löste hälften rätt.

  • Jag gissade svaret två gånger!

  • Jag skriver i kommentarerna

14 användare röstade. 10 användare avstod från att rösta.

Källa: will.com

Lägg en kommentar