Følger i fodsporene på Highload++ Siberia 2019 - 8 opgaver på Oracle

Hi!

Den 24.-25. juni blev konferencen Highload++ Siberia 2019 afholdt i Novosibirsk. Vores fyre var der også rapport "Oracle containerdatabaser (CDB/PDB) og deres praktiske anvendelse til softwareudvikling", vi udgiver en tekstversion lidt senere. Det var fedt, tak olegbunin for organisationen, såvel som for alle der kom.

Følger i fodsporene på Highload++ Siberia 2019 - 8 opgaver på Oracle
I dette indlæg vil vi gerne dele med dig de problemer, vi havde på vores stand, så du kan teste din Oracle-viden. Under snittet er 8 opgaver, svarmuligheder og forklaring.

Hvad er den maksimale sekvensværdi, vi vil se som et resultat af at udføre følgende script?

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, der vil være en fejl

SvarIfølge Oracle-dokumentation (citeret fra 8.1.6):
Inden for en enkelt SQL-sætning vil Oracle kun øge sekvensen én gang pr. række. Hvis en sætning indeholder mere end én reference til NEXTVAL for en sekvens, øger Oracle sekvensen én gang og returnerer den samme værdi for alle forekomster af NEXTVAL. Hvis en sætning indeholder referencer til både CURRVAL og NEXTVAL, øger Oracle sekvensen og returnerer den samme værdi for både CURRVAL og NEXTVAL uanset deres rækkefølge i sætningen.

Således den maksimale værdi vil svare til antallet af linjer, det vil sige 5.

Hvor mange rækker vil der være i tabellen som et resultat af at køre følgende script?

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

SvarIfølge Oracle-dokumentation (citeret fra 11.2):

Før en SQL-sætning udføres, markerer Oracle et implicit lagringspunkt (ikke tilgængeligt for dig). Så, hvis sætningen mislykkes, ruller Oracle den automatisk tilbage og returnerer den relevante fejlkode til SQLCODE i SQLCA. For eksempel, hvis en INSERT-sætning forårsager en fejl ved at forsøge at indsætte en dubletværdi i et unikt indeks, rulles sætningen tilbage.

Opkald til HP fra klienten betragtes og behandles også som en enkelt erklæring. Således afsluttes det første HP-opkald med succes efter at have indsat tre poster; det andet HP-opkald slutter med en fejl og ruller den fjerde post tilbage, som det lykkedes at indsætte; det tredje opkald mislykkes, og der er tre poster i tabellen.

Hvor mange rækker vil der være i tabellen som et resultat af at køre følgende script?

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

SvarIfølge Oracle-dokumentation (citeret fra 11.2):

En kontrolbegrænsning lader dig angive en betingelse, som hver række i tabellen skal opfylde. For at opfylde begrænsningen skal hver række i tabellen gøre betingelsen enten SAND eller ukendt (på grund af en null). Når Oracle evaluerer en kontrolbetingelsesbetingelse for en bestemt række, refererer eventuelle kolonnenavne i betingelsen til kolonneværdierne i den pågældende række.

Værdien null vil således bestå kontrollen, og den anonyme blokering vil blive udført med succes indtil et forsøg på at indsætte værdien 3. Herefter vil fejlhåndteringsblokken rydde undtagelsen, ingen rollback vil ske, og der vil være fire rækker tilbage i tabellen med værdierne 1, null, 2 og null igen.

Hvilke værdipar vil optage den samme mængde plads i blokken?

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 og X
  • B og Y
  • C og K
  • C og Z
  • K og Z
  • jeg og J
  • J og X
  • Alle anført

SvarHer er uddrag fra dokumentationen (12.1.0.2) om lagring af forskellige typer data i Oracle.

CHAR datatype
CHAR-datatypen angiver en tegnstreng med fast længde i databasens tegnsæt. Du angiver databasens tegnsæt, når du opretter din database. Oracle sikrer, at alle værdier, der er gemt i en CHAR-kolonne, har den længde, der er angivet efter størrelse i den valgte længdesemantik. Hvis du indsætter en værdi, der er kortere end kolonnelængden, vil Oracle blank-pads værdien til kolonnelængden.

VARCHAR2 datatype
VARCHAR2-datatypen angiver en tegnstreng med variabel længde i databasens tegnsæt. Du angiver databasens tegnsæt, når du opretter din database. Oracle gemmer en tegnværdi i en VARCHAR2-kolonne nøjagtigt, som du angiver den, uden blank udfyldning, forudsat at værdien ikke overstiger kolonnens længde.

NUMBER Datatype
Datatypen NUMBER gemmer nul samt positive og negative faste tal med absolutte værdier fra 1.0 x 10-130 til men ikke inklusive 1.0 x 10126. Hvis du angiver et aritmetisk udtryk, hvis værdi har en absolut værdi større end eller lig med 1.0 x 10126, så returnerer Oracle en fejl. Hver NUMBER-værdi kræver fra 1 til 22 bytes. Med dette i betragtning kan kolonnestørrelsen i bytes for en bestemt numerisk dataværdi NUMBER(p), hvor p er præcisionen af ​​en given værdi, beregnes ved hjælp af følgende formel: RUND((længde(p)+s)/2))+1 hvor s er lig nul, hvis tallet er positivt, og s er lig med 1, hvis tallet er negativt.

Lad os desuden tage et uddrag af dokumentationen om lagring af Null-værdier.

Et null er fraværet af en værdi i en kolonne. Nuller angiver manglende, ukendte eller uanvendelige data. Nuller gemmes i databasen, hvis de falder mellem kolonner med dataværdier. I disse tilfælde kræver de 1 byte for at lagre længden af ​​kolonnen (nul). Efterfølgende nuller i en række kræver ingen lagring, fordi en ny rækkeoverskrift signalerer, at de resterende kolonner i den foregående række er nul. For eksempel, hvis de sidste tre kolonner i en tabel er nul, gemmes der ingen data for disse kolonner.

Baseret på disse data bygger vi ræsonnementer. Vi antager, at databasen bruger AL32UTF8-kodning. I denne kodning vil russiske bogstaver optage 2 bytes.

1) A og X, værdien af ​​felt a 'Y' tager 1 byte, værdien af ​​felt x 'D' tager 2 bytes
2) B og Y, 'Vasya' i b værdien vil blive polstret med mellemrum op til 10 tegn og vil tage 14 bytes, 'Vasya' i d vil tage 8 bytes.
3) C og K. Begge felter har værdien NULL, efter dem er der signifikante felter, så de fylder 1 byte.
4) C og Z. Begge felter har værdien NULL, men felt Z er det sidste i tabellen, så det fylder ikke (0 bytes). Felt C optager 1 byte.
5) K og Z. Svarende til det foregående tilfælde. Værdien i K-feltet optager 1 byte, i Z – 0.
6) I og J. Ifølge dokumentationen vil begge værdier tage 2 bytes. Vi beregner længden ved hjælp af formlen taget fra dokumentationen: round( (1 + 0)/2) +1 = 1 + 1 = 2.
7) J og X. Værdien i J-feltet vil tage 2 bytes, værdien i X-feltet vil tage 2 bytes.

I alt er de korrekte muligheder: C og K, I og J, J og X.

Hvad vil klyngefaktoren for T_I-indekset være?

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

  • Omkring tiere
  • Omkring hundreder
  • Omkring tusinder
  • Omkring titusinder

SvarIfølge Oracle-dokumentation (citeret fra 12.1):

For et B-træindeks måler indeksklyngefaktoren den fysiske gruppering af rækker i forhold til en indeksværdi.

Indeksklyngefaktoren hjælper optimeringsværktøjet med at beslutte, om en indeksscanning eller en fuld tabelscanning er mere effektiv for visse forespørgsler). En lav klyngefaktor indikerer en effektiv indeksscanning.

En klyngefaktor, der er tæt på antallet af blokke i en tabel, indikerer, at rækkerne er fysisk ordnet i tabelblokkene efter indeksnøglen. Hvis databasen udfører en fuld tabelscanning, har databasen en tendens til at hente rækkerne, da de er lagret på disken sorteret efter indeksnøglen. En klyngefaktor, der er tæt på antallet af rækker, indikerer, at rækkerne er spredt tilfældigt over databaseblokkene i forhold til indeksnøglen. Hvis databasen udfører en fuld tabelscanning, vil databasen ikke hente rækker i nogen sorteret rækkefølge efter denne indeksnøgle.

I dette tilfælde er dataene ideelt sorteret, så klyngefaktoren vil være lig med eller tæt på antallet af besatte blokke i tabellen. For en standard blokstørrelse på 8 kilobyte kan du forvente, at omkring tusinde smalle talværdier passer ind i en blok, så antallet af blokke og som et resultat vil klyngefaktoren være omkring tiere.

Ved hvilke værdier af N vil følgende script blive udført med succes i en almindelig database med standardindstillinger?

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

SvarIfølge Oracle-dokumentation (citeret fra 11.2):

Logiske databasegrænser

Vare
Type grænse
Grænseværdi

Indexes
Samlet størrelse af indekseret kolonne
75 % af databaseblokstørrelsen minus nogle overhead

Den samlede størrelse af indekserede kolonner bør således ikke overstige 6Kb. Hvad der derefter sker, afhænger af den valgte basiskodning. For AL32UTF8-kodning kan et tegn maksimalt optage 4 bytes, så i værste fald vil omkring 6 tegn passe ind i 1500 kilobytes. Derfor vil Oracle ikke tillade indeksoprettelse ved N = 400 (når den værste nøglelængde er 1600 tegn * 4 bytes + rækkevidde), mens ved N = 200 (eller mindre) oprettelse af indekset vil fungere uden problemer.

INSERT-operatøren med APPEND-tip er designet til at indlæse data i direkte tilstand. Hvad sker der, hvis det sættes på bordet, som aftrækkeren hænger på?

  • Dataene indlæses i direkte tilstand, triggeren vil fungere som forventet
  • Dataene indlæses i direkte tilstand, men triggeren vil ikke blive udført
  • Dataene vil blive indlæst i konventionel tilstand, triggeren vil fungere som den skal
  • Dataene vil blive indlæst i konventionel tilstand, men triggeren vil ikke blive udført
  • Dataene vil ikke blive indlæst, en fejl vil blive registreret

SvarDybest set er dette mere et spørgsmål om logik. For at finde det rigtige svar vil jeg foreslå følgende ræsonnementmodel:

  1. Indsættelse i direkte tilstand udføres ved direkte dannelse af en datablok, uden om SQL-motoren, som sikrer høj hastighed. Det er således meget vanskeligt, hvis ikke umuligt, at sikre udførelsen af ​​udløseren, og det nytter ikke noget, da det stadig vil bremse indføringen radikalt.
  2. Undladelse af at udføre triggeren vil føre til, at hvis dataene i tabellen er de samme, vil status for databasen som helhed (andre tabeller) afhænge af den tilstand, hvori disse data blev indsat. Dette vil naturligvis ødelægge dataintegriteten og kan ikke anvendes som en løsning i produktionen.
  3. Manglende evne til at udføre den ønskede handling behandles generelt som en fejl. Men her skal vi huske, at APPEND er et hint, og den generelle logik i hints er, at de tages i betragtning, hvis det er muligt, men hvis ikke, udføres operatøren uden at tage hint i betragtning.

Så det forventede svar er dataene vil blive indlæst i normal (SQL) tilstand, udløseren udløses.

Ifølge Oracle-dokumentation (citeret fra 8.04):

Overtrædelser af begrænsningerne vil medføre, at sætningen udføres serielt ved brug af den konventionelle indsættelsessti uden advarsler eller fejlmeddelelser. En undtagelse er begrænsningen af ​​sætninger, der får adgang til den samme tabel mere end én gang i en transaktion, hvilket kan forårsage fejlmeddelelser.
Hvis f.eks. triggere eller referenceintegritet er til stede på bordet, ignoreres APPEND-hintet, når du forsøger at bruge INSERT med direkte belastning (seriel eller parallel), såvel som PARALLEL-hint eller klausul, hvis nogen.

Hvad sker der, når følgende script udføres?

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

  • Succesfuld afslutning
  • Fejl på grund af syntaksfejl
  • Fejl: Autonom transaktion er ikke gyldig
  • Fejl relateret til overskridelse af den maksimale opkaldsindlejring
  • Fejl ved brud på udenlandsk nøgle
  • Fejl relateret til låse

SvarTabellen og triggeren er oprettet helt korrekt, og denne operation bør ikke føre til problemer. Autonome transaktioner i en trigger er også tilladt, ellers ville f.eks. logning ikke være mulig.

Efter indsættelse af den første række, vil en vellykket udløserudløsning medføre, at den anden række indsættes, hvilket får udløseren til at udløse igen, indsættelse af en tredje række, og så videre, indtil erklæringen mislykkedes på grund af overskridelse af den maksimale indlejring af opkald. En anden subtil pointe spiller dog ind. På det tidspunkt, hvor triggeren udføres, er commit endnu ikke afsluttet for den første indsatte post. Derfor forsøger en trigger, der kører i en autonom transaktion, at indsætte en række i tabellen, der refererer til en fremmednøgle til en post, der endnu ikke er blevet committet. Dette resulterer i en ventetid (den autonome transaktion venter på, at hovedtransaktionen forpligter sig for at se, om den kan indsætte data), og samtidig venter hovedtransaktionen på, at den autonome transaktion fortsætter med at virke efter triggeren. Der opstår et dødvande, og som følge heraf annulleres den autonome transaktion på grund af årsager relateret til låse.

Kun registrerede brugere kan deltage i undersøgelsen. Log ind, Vær venlig.

var det svært at?

  • Som to fingre besluttede jeg straks alt korrekt.

  • Ikke rigtig, jeg tog fejl på et par spørgsmål.

  • Jeg løste halvdelen rigtigt.

  • Jeg gættede svaret to gange!

  • Jeg skriver i kommentarerne

14 brugere stemte. 10 brugere undlod at stemme.

Kilde: www.habr.com

Tilføj en kommentar