Følger i fotsporene til Highload++ Siberia 2019 - 8 oppgaver på Oracle

Hei!

24. – 25. juni ble konferansen Highload++ Siberia 2019 avholdt i Novosibirsk. Gutta våre var der også rapportere "Oracle containerdatabaser (CDB/PDB) og deres praktiske bruk for programvareutvikling", vil vi publisere en tekstversjon litt senere. Det var kult, takk olegbunin for organisasjonen, samt for alle som kom.

Følger i fotsporene til Highload++ Siberia 2019 - 8 oppgaver på Oracle
I dette innlegget vil vi gjerne dele med deg problemene vi hadde på standen vår, slik at du kan teste Oracle-kunnskapen din. Under kuttet er 8 oppgaver, svaralternativer og forklaring.

Hva er den maksimale sekvensverdien vi vil se som et resultat av å kjøre følgende 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
  • Nei, det vil være en feil

svarI følge Oracle-dokumentasjon (sitert fra 8.1.6):
Innenfor en enkelt SQL-setning vil Oracle øke sekvensen bare én gang per rad. Hvis en setning inneholder mer enn én referanse til NEXTVAL for en sekvens, øker Oracle sekvensen én gang og returnerer samme verdi for alle forekomster av NEXTVAL. Hvis en setning inneholder referanser til både CURRVAL og NEXTVAL, øker Oracle sekvensen og returnerer samme verdi for både CURRVAL og NEXTVAL uavhengig av rekkefølgen i setningen.

Dermed blir maksimumsverdien vil tilsvare antall linjer, det vil si 5.

Hvor mange rader vil være i tabellen som et resultat av å kjøre følgende 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

svarI følge Oracle-dokumentasjon (sitert fra 11.2):

Før du utfører en SQL-setning, merker Oracle et implisitt lagringspunkt (ikke tilgjengelig for deg). Deretter, hvis setningen mislykkes, ruller Oracle den tilbake automatisk og returnerer den aktuelle feilkoden til SQLCODE i SQLCA. For eksempel, hvis en INSERT-setning forårsaker en feil ved å prøve å sette inn en duplikatverdi i en unik indeks, rulles setningen tilbake.

Å ringe HP fra klienten betraktes og behandles også som en enkelt erklæring. Dermed fullføres det første HP-anropet vellykket, etter å ha satt inn tre poster; det andre HP-anropet avsluttes med en feil og ruller tilbake den fjerde posten som den klarte å sette inn; den tredje samtalen mislykkes, og det er tre poster i tabellen.

Hvor mange rader vil være i tabellen som et resultat av å kjøre følgende 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

svarI følge Oracle-dokumentasjon (sitert fra 11.2):

En kontrollbegrensning lar deg spesifisere en betingelse som hver rad i tabellen må tilfredsstille. For å tilfredsstille begrensningen, må hver rad i tabellen gjøre betingelsen enten TRUE eller ukjent (på grunn av en null). Når Oracle evaluerer en kontrollbegrensningsbetingelse for en bestemt rad, refererer eventuelle kolonnenavn i tilstanden til kolonneverdiene i den raden.

Dermed vil verdien null bestå sjekken, og den anonyme blokkeringen vil bli utført med suksess inntil et forsøk på å sette inn verdien 3. Etter dette vil feilhåndteringsblokken fjerne unntaket, ingen tilbakerulling vil skje, og det vil være fire rader igjen i tabellen med verdier 1, null, 2 og null igjen.

Hvilke verdipar vil ta like mye plass 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
  • Alt oppført

svarHer er utdrag fra dokumentasjonen (12.1.0.2) om lagring av ulike typer data i Oracle.

CHAR datatype
CHAR-datatypen spesifiserer en tegnstreng med fast lengde i databasetegnsettet. Du spesifiserer databasetegnsettet når du oppretter databasen. Oracle sørger for at alle verdier som er lagret i en CHAR-kolonne har lengden spesifisert etter størrelse i den valgte lengdesemantikken. Hvis du setter inn en verdi som er kortere enn kolonnelengden, vil Oracle blank-padsere verdien til kolonnelengden.

VARCHAR2 datatype
VARCHAR2-datatypen spesifiserer en tegnstreng med variabel lengde i databasetegnsettet. Du spesifiserer databasetegnsettet når du oppretter databasen. Oracle lagrer en tegnverdi i en VARCHAR2-kolonne nøyaktig slik du spesifiserer den, uten blank-utfylling, forutsatt at verdien ikke overskrider lengden på kolonnen.

NUMBER Datatype
Datatypen NUMBER lagrer null samt positive og negative faste tall med absolutte verdier fra 1.0 x 10-130 til men ikke inkludert 1.0 x 10126. Hvis du spesifiserer et aritmetisk uttrykk hvis verdi har en absoluttverdi større enn eller lik 1.0 x 10126, så returnerer Oracle en feil. Hver NUMBER-verdi krever fra 1 til 22 byte. Når dette tas i betraktning, kan kolonnestørrelsen i byte for en bestemt numerisk dataverdi NUMBER(p), der p er presisjonen til en gitt verdi, beregnes ved å bruke følgende formel: RUND((lengde(p)+s)/2))+1 hvor s er lik null hvis tallet er positivt, og s er lik 1 hvis tallet er negativt.

La oss i tillegg ta et utdrag fra dokumentasjonen om lagring av nullverdier.

En null er fraværet av en verdi i en kolonne. Nullverdier indikerer manglende, ukjente eller uanvendelige data. Nullverdier lagres i databasen hvis de faller mellom kolonner med dataverdier. I disse tilfellene krever de 1 byte for å lagre lengden på kolonnen (null). Etterfølgende nullverdier i en rad krever ingen lagring fordi en ny radoverskrift signaliserer at de gjenværende kolonnene i forrige rad er null. For eksempel, hvis de tre siste kolonnene i en tabell er null, lagres ingen data for disse kolonnene.

Basert på disse dataene bygger vi resonnement. Vi antar at databasen bruker AL32UTF8-koding. I denne kodingen vil russiske bokstaver oppta 2 byte.

1) A og X, verdien av felt a 'Y' tar 1 byte, verdien av felt x 'D' tar 2 byte
2) B og Y, 'Vasya' i b verdien vil fylles med mellomrom på opptil 10 tegn og vil ta 14 byte, 'Vasya' i d vil ta 8 byte.
3) C og K. Begge feltene har verdien NULL, etter dem er det signifikante felt, så de opptar 1 byte.
4) C og Z. Begge feltene har verdien NULL, men felt Z er det siste i tabellen, så det tar ikke plass (0 byte). Felt C opptar 1 byte.
5) K og Z. Ligner på forrige tilfelle. Verdien i K-feltet opptar 1 byte, i Z – 0.
6) I og J. I følge dokumentasjonen vil begge verdiene ta 2 byte. Vi beregner lengden ved å bruke formelen hentet fra dokumentasjonen: round( (1 + 0)/2) +1 = 1 + 1 = 2.
7) J og X. Verdien i J-feltet vil ta 2 byte, verdien i X-feltet vil ta 2 byte.

Totalt er de riktige alternativene: C og K, I og J, J og X.

Hva omtrent vil være klyngefaktoren til T_I-indeksen?

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

  • Omtrent ti
  • Omtrent hundrevis
  • Omtrent tusenvis
  • Omtrent titusenvis

svarI følge Oracle-dokumentasjon (sitert fra 12.1):

For en B-treindeks måler indeksklyngefaktoren den fysiske grupperingen av rader i forhold til en indeksverdi.

Indeksklyngefaktoren hjelper optimalisereren med å avgjøre om en indeksskanning eller full tabellskanning er mer effektiv for visse spørringer). En lav klyngefaktor indikerer en effektiv indeksskanning.

En klyngefaktor som er nær antall blokker i en tabell indikerer at radene er fysisk sortert i tabellblokkene etter indeksnøkkelen. Hvis databasen utfører en full tabellskanning, har databasen en tendens til å hente radene ettersom de er lagret på disk sortert etter indeksnøkkelen. En klyngefaktor som er nær antall rader indikerer at radene er spredt tilfeldig over databaseblokkene i forhold til indeksnøkkelen. Hvis databasen utfører en full tabellskanning, vil ikke databasen hente rader i noen sortert rekkefølge etter denne indeksnøkkelen.

I dette tilfellet er dataene ideelt sortert, slik at klyngefaktoren vil være lik eller nær antall okkuperte blokker i tabellen. For en standard blokkstørrelse på 8 kilobyte kan du forvente at rundt tusen smale tallverdier vil passe inn i en blokk, så antallet blokker og som et resultat vil klyngefaktoren være omtrent ti.

Ved hvilke verdier av N vil følgende skript bli utført i en vanlig database med standardinnstillinger?

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

svarI følge Oracle-dokumentasjon (sitert fra 11.2):

Logiske databasegrenser

Sak
Type grense
Grenseverdi

Indekser
Total størrelse på indeksert kolonne
75 % av databaseblokkstørrelsen minus noe overhead

Den totale størrelsen på indekserte kolonner bør derfor ikke overstige 6Kb. Hva som skjer videre avhenger av den valgte basiskodingen. For AL32UTF8-koding kan ett tegn oppta maksimalt 4 byte, så i verste fall vil ca. 6 tegn passe inn i 1500 kilobyte. Derfor vil Oracle ikke tillate indeksoppretting ved N = 400 (når den verste nøkkellengden er 1600 tegn * 4 byte + rekkevidde), mens ved N = 200 (eller mindre) å lage indeksen vil fungere uten problemer.

INSERT-operatøren med APPEND-tipset er designet for å laste data i direkte modus. Hva skjer hvis den brukes på bordet som utløseren henger på?

  • Dataene vil bli lastet i direkte modus, utløseren vil fungere som forventet
  • Dataene vil bli lastet i direkte modus, men utløseren vil ikke bli utført
  • Dataene vil bli lastet i konvensjonell modus, triggeren vil fungere som den skal
  • Dataene vil bli lastet i konvensjonell modus, men utløseren vil ikke bli utført
  • Dataene vil ikke bli lastet, en feil vil bli registrert

svarI utgangspunktet er dette mer et spørsmål om logikk. For å finne det riktige svaret vil jeg foreslå følgende resonneringsmodell:

  1. Innsetting i direkte modus utføres ved direkte dannelse av en datablokk, utenom SQL-motoren, som sikrer høy hastighet. Dermed er det svært vanskelig, om ikke umulig å sikre utførelse av utløseren, og det er ingen vits i dette, siden det fortsatt vil redusere innsettingen radikalt.
  2. Unnlatelse av å utføre triggeren vil føre til at hvis dataene i tabellen er de samme, vil tilstanden til databasen som helhet (andre tabeller) avhenge av modusen som disse dataene ble satt inn i. Dette vil åpenbart ødelegge dataintegriteten og kan ikke brukes som løsning i produksjonen.
  3. Manglende evne til å utføre den forespurte operasjonen blir vanligvis behandlet som en feil. Men her bør vi huske at APPEND er et hint, og den generelle logikken til hint er at de tas i betraktning hvis mulig, men hvis ikke, blir operatøren utført uten å ta hint i betraktning.

Så det forventede svaret er dataene vil bli lastet i normal (SQL) modus, utløseren utløses.

I følge Oracle-dokumentasjon (sitert fra 8.04):

Brudd på restriksjonene vil føre til at setningen kjøres serielt, ved bruk av den konvensjonelle innsettingsbanen, uten advarsler eller feilmeldinger. Et unntak er begrensningen på utsagn som får tilgang til samme tabell mer enn én gang i en transaksjon, noe som kan forårsake feilmeldinger.
For eksempel, hvis triggere eller referanseintegritet er tilstede på bordet, vil APPEND-hintet bli ignorert når du prøver å bruke INSERT med direkte belastning (seriell eller parallell), så vel som PARALLELL-hintet eller klausulen, hvis noen.

Hva vil skje når følgende skript kjø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);

  • Vellykket gjennomføring
  • Feil på grunn av syntaksfeil
  • Feil: Autonom transaksjon er ikke gyldig
  • Feil relatert til overskridelse av maksimalt anropsnesting
  • Feil ved brudd på utenlandsk nøkkel
  • Feil relatert til låser

svarTabellen og utløseren er opprettet helt riktig, og denne operasjonen bør ikke føre til problemer. Autonome transaksjoner i en trigger er også tillatt, ellers ville for eksempel ikke logging vært mulig.

Etter å ha satt inn den første raden, vil en vellykket utløseravfyring føre til at den andre raden settes inn, noe som får utløseren til å utløses igjen, sette inn en tredje rad, og så videre til setningen mislyktes på grunn av overskridelse av den maksimale nesting av samtaler. Imidlertid spiller et annet subtilt poeng inn. På det tidspunktet triggeren utføres, er commit ennå ikke fullført for den første innsatte posten. Derfor prøver en utløser som kjører i en autonom transaksjon å sette inn i tabellen en rad som refererer til en fremmednøkkel til en post som ennå ikke har blitt forpliktet. Dette resulterer i en venting (den autonome transaksjonen venter på at hovedtransaksjonen skal forplikte seg for å se om den kan sette inn data) og samtidig venter hovedtransaksjonen på at den autonome transaksjonen skal fortsette å fungere etter triggeren. En vranglås oppstår, og som et resultat kanselleres den autonome transaksjonen på grunn av årsaker knyttet til låser.

Kun registrerte brukere kan delta i undersøkelsen. Logg inn, vær så snill.

var det vanskelig å?

  • Som to fingre bestemte jeg meg umiddelbart for alt riktig.

  • Egentlig ikke, jeg tok feil på et par spørsmål.

  • Jeg løste halvparten riktig.

  • Jeg gjettet svaret to ganger!

  • Jeg skal skrive i kommentarfeltet

14 brukere stemte. 10 brukere avsto.

Kilde: www.habr.com

Legg til en kommentar