In de voetsporen van Highload++ Siberia 2019 - 8 taken op Oracle

Hey there!

Op 24-25 juni vond de Highload++ Siberia 2019 conferentie plaats in Novosibirsk, onze jongens waren er ook verslag doen van “Oracle containerdatabases (CDB/PDB) en hun praktisch gebruik voor softwareontwikkeling”, zullen we later een tekstversie publiceren. Het was cool, bedankt olegbunine voor de organisatie, maar ook voor iedereen die kwam.

In de voetsporen van Highload++ Siberia 2019 - 8 taken op Oracle
In dit bericht willen we graag de problemen die we op onze stand tegenkwamen met u delen, zodat u uw Oracle-kennis kunt testen. Onder de snede staan ​​8 problemen, antwoordopties en uitleg.

Wat is de maximale reekswaarde die we zullen zien als resultaat van het uitvoeren van het volgende 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
  • Nee, er zal een fout optreden

BeantwoordenVolgens Oracle-documentatie (geciteerd uit 8.1.6):
Binnen een enkele SQL-instructie verhoogt Oracle de reeks slechts één keer per rij. Als een instructie meer dan één verwijzing naar NEXTVAL voor een reeks bevat, verhoogt Oracle de reeks één keer en retourneert dezelfde waarde voor alle exemplaren van NEXTVAL. Als een instructie verwijzingen naar zowel CURRVAL als NEXTVAL bevat, verhoogt Oracle de reeks en retourneert dezelfde waarde voor zowel CURRVAL als NEXTVAL, ongeacht hun volgorde binnen de instructie.

Dus de de maximale waarde komt overeen met het aantal regels, dat wil zeggen 5.

Hoeveel rijen zullen er in de tabel staan ​​als gevolg van het uitvoeren van het volgende 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

BeantwoordenVolgens Oracle-documentatie (geciteerd uit 11.2):

Voordat een SQL-instructie wordt uitgevoerd, markeert Oracle een impliciet opslagpunt (niet beschikbaar voor u). Als de instructie vervolgens mislukt, draait Oracle deze automatisch terug en retourneert de toepasselijke foutcode naar SQLCODE in de SQLCA. Als een INSERT-instructie bijvoorbeeld een fout veroorzaakt door te proberen een dubbele waarde in een unieke index in te voegen, wordt de instructie ongedaan gemaakt.

Ook het bellen naar HP vanaf de klant wordt als één opgave beschouwd en verwerkt. De eerste HP-oproep wordt dus met succes voltooid, nadat er drie records zijn ingevoegd; de tweede HP-oproep eindigt met een fout en draait het vierde record terug dat het heeft kunnen invoegen; de derde oproep mislukt, en er zijn drie records in de tabel.

Hoeveel rijen zullen er in de tabel staan ​​als gevolg van het uitvoeren van het volgende 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

BeantwoordenVolgens Oracle-documentatie (geciteerd uit 11.2):

Met een controlebeperking kunt u een voorwaarde opgeven waaraan elke rij in de tabel moet voldoen. Om aan de beperking te voldoen, moet elke rij in de tabel de voorwaarde WAAR of onbekend maken (vanwege een nul). Wanneer Oracle een controlebeperkingsvoorwaarde voor een bepaalde rij evalueert, verwijzen alle kolomnamen in de voorwaarde naar de kolomwaarden in die rij.

De waarde null zal dus de controle doorstaan ​​en het anonieme blok zal met succes worden uitgevoerd tot een poging om de waarde 3 in te voegen. Hierna zal het foutafhandelingsblok de uitzondering wissen, er zal geen rollback plaatsvinden en Er blijven vier rijen over in de tabel met waarden 1, null, 2 en nog eens null.

Welke waardenparen nemen dezelfde hoeveelheid ruimte in het blok in beslag?

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 en X
  • B en Y
  • C en K
  • C en Z
  • K en Z
  • ik en J
  • J en X
  • Allemaal vermeld

BeantwoordenHier zijn fragmenten uit de documentatie (12.1.0.2) over het opslaan van verschillende soorten gegevens in Oracle.

CHAR-gegevenstype
Het CHAR-gegevenstype specificeert een tekenreeks met een vaste lengte in de databasetekenset. U geeft de databasetekenset op wanneer u uw database maakt. Oracle zorgt ervoor dat alle waarden die in een CHAR-kolom zijn opgeslagen de lengte hebben die is opgegeven per grootte in de geselecteerde lengtesemantiek. Als u een waarde invoegt die korter is dan de kolomlengte, voegt Oracle de waarde blanco toe aan de kolomlengte.

VARCHAR2-gegevenstype
Het gegevenstype VARCHAR2 specificeert een tekenreeks met variabele lengte in de databasetekenset. U geeft de databasetekenset op wanneer u uw database maakt. Oracle slaat een tekenwaarde op in een VARCHAR2-kolom, precies zoals u deze opgeeft, zonder enige opvulling, op voorwaarde dat de waarde de lengte van de kolom niet overschrijdt.

NUMBER gegevenstype
Het gegevenstype NUMBER slaat zowel nul op als positieve en negatieve vaste getallen met absolute waarden van 1.0 x 10-130 tot maar niet inclusief 1.0 x 10126. Als u een rekenkundige uitdrukking opgeeft waarvan de waarde een absolute waarde heeft die groter is dan of gelijk is aan 1.0 x 10126, waarna Oracle een fout retourneert. Elke NUMBER-waarde vereist 1 tot 22 bytes. Hiermee rekening houdend kan de kolomgrootte in bytes voor een bepaalde numerieke gegevenswaarde NUMBER(p), waarbij p de precisie van een gegeven waarde is, worden berekend met behulp van de volgende formule: RONDE((lengte(p)+s)/2))+1 waarbij s gelijk is aan nul als het getal positief is, en s gelijk is aan 1 als het getal negatief is.

Laten we daarnaast een fragment uit de documentatie nemen over het opslaan van nulwaarden.

Een null is de afwezigheid van een waarde in een kolom. Nullen duiden op ontbrekende, onbekende of niet-toepasbare gegevens. Null-waarden worden in de database opgeslagen als ze tussen kolommen met gegevenswaarden vallen. In deze gevallen hebben ze 1 byte nodig om de lengte van de kolom op te slaan (nul). Achterliggende null-waarden in een rij vereisen geen opslag omdat een nieuwe rijkop aangeeft dat de resterende kolommen in de vorige rij nul zijn. Als de laatste drie kolommen van een tabel bijvoorbeeld nul zijn, worden er voor deze kolommen geen gegevens opgeslagen.

Op basis van deze gegevens bouwen we een redenering op. We gaan ervan uit dat de database AL32UTF8-codering gebruikt. In deze codering zullen Russische letters 2 bytes in beslag nemen.

1) A en X, de waarde van veld a 'Y' duurt 1 byte, de waarde van veld x 'D' duurt 2 bytes
2) B en Y, 'Vasya' in b de waarde wordt opgevuld met spaties van maximaal 10 tekens en neemt 14 bytes in beslag, 'Vasya' in d neemt 8 bytes in beslag.
3) C en K. Beide velden hebben de waarde NULL, daarna zijn er significante velden, dus ze bezetten 1 byte.
4) C en Z. Beide velden hebben de waarde NULL, maar veld Z is het laatste in de tabel en neemt dus geen ruimte in beslag (0 bytes). Veld C beslaat 1 byte.
5) K en Z. Vergelijkbaar met het vorige geval. De waarde in het K-veld beslaat 1 byte, in Z – 0.
6) I en J. Volgens de documentatie zullen beide waarden 2 bytes in beslag nemen. We berekenen de lengte met behulp van de formule uit de documentatie: round( (1 + 0)/2) +1 = 1 + 1 = 2.
7) J en X. De waarde in het J-veld neemt 2 bytes in beslag, de waarde in het X-veld neemt 2 bytes in beslag.

In totaal zijn de juiste opties: C en K, I en J, J en X.

Wat zal ongeveer de clusteringsfactor van de T_I-index zijn?

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

  • Ongeveer tientallen
  • Ongeveer honderden
  • Ongeveer duizenden
  • Ongeveer tienduizenden

BeantwoordenVolgens Oracle-documentatie (geciteerd uit 12.1):

Voor een B-tree-index meet de indexclusterfactor de fysieke groepering van rijen in relatie tot een indexwaarde.

De indexclusteringsfactor helpt de optimalisatie om te beslissen of een indexscan of een volledige tabelscan efficiënter is voor bepaalde zoekopdrachten). Een lage clusteringsfactor duidt op een efficiënte indexscan.

Een clusterfactor die dicht bij het aantal blokken in een tabel ligt, geeft aan dat de rijen fysiek in de tabelblokken zijn geordend op basis van de indexsleutel. Als de database een volledige tabelscan uitvoert, heeft de database de neiging de rijen op te halen zoals deze op schijf zijn opgeslagen, gesorteerd op de indexsleutel. Een clusteringsfactor die dicht bij het aantal rijen ligt, geeft aan dat de rijen willekeurig over de databaseblokken verspreid zijn in relatie tot de indexsleutel. Als de database een volledige tabelscan uitvoert, haalt de database geen rijen op in welke volgorde dan ook met deze indexsleutel.

In dit geval worden de gegevens idealiter gesorteerd, zodat de clusterfactor gelijk is aan of dichtbij het aantal bezette blokken in de tabel. Voor een standaard blokgrootte van 8 kilobytes kun je verwachten dat er ongeveer duizend smalle getalswaarden in één blok passen, dus het aantal blokken, en als gevolg daarvan, de clusterfactor zal zijn ongeveer tientallen.

Bij welke waarden van N wordt het volgende script succesvol uitgevoerd in een reguliere database met standaardinstellingen?

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

BeantwoordenVolgens Oracle-documentatie (geciteerd uit 11.2):

Logische databaselimieten

item
Type limiet
Grenswaarde

Indexen
Totale grootte van de geïndexeerde kolom
75% van de databaseblokgrootte minus wat overhead

De totale grootte van de geïndexeerde kolommen mag dus niet groter zijn dan 6 KB. Wat er vervolgens gebeurt, hangt af van de geselecteerde basiscodering. Voor AL32UTF8-codering kan één teken maximaal 4 bytes in beslag nemen, dus in het ergste geval passen er ongeveer 6 tekens in 1500 kilobytes. Daarom zal Oracle het maken van indexen bij N = 400 niet toestaan ​​(wanneer de sleutellengte in het slechtste geval 1600 tekens * 4 bytes + rowid-lengte is), terwijl bij N = 200 (of minder) het maken van de index zal zonder problemen werken.

De INSERT-operator met de APPEND-hint is ontworpen om gegevens in directe modus te laden. Wat gebeurt er als het wordt toegepast op de tafel waaraan de trigger hangt?

  • De gegevens worden in de directe modus geladen, de trigger werkt zoals verwacht
  • De data worden in de directe modus geladen, maar de trigger wordt niet uitgevoerd
  • De gegevens worden in de conventionele modus geladen, de trigger werkt zoals het hoort
  • De data worden in de conventionele modus geladen, maar de trigger wordt niet uitgevoerd
  • De gegevens worden niet geladen, er wordt een fout geregistreerd

BeantwoordenKortom, dit is meer een kwestie van logica. Om het juiste antwoord te vinden, zou ik het volgende redeneermodel willen voorstellen:

  1. Invoeging in de directe modus wordt uitgevoerd door directe vorming van een datablok, waarbij de SQL-engine wordt omzeild, wat een hoge snelheid garandeert. Het garanderen van de uitvoering van de trigger is dus erg moeilijk, zo niet onmogelijk, en dit heeft geen zin, omdat het de invoeging nog steeds radicaal zal vertragen.
  2. Het niet uitvoeren van de trigger zal ertoe leiden dat, als de gegevens in de tabel hetzelfde zijn, de toestand van de database als geheel (andere tabellen) zal afhangen van de modus waarin deze gegevens zijn ingevoegd. Dit zal uiteraard de data-integriteit vernietigen en kan niet als oplossing in de productie worden toegepast.
  3. Het onvermogen om de gevraagde bewerking uit te voeren wordt doorgaans als een fout beschouwd. Maar hier moeten we onthouden dat APPEND een hint is, en de algemene logica van hints is dat er indien mogelijk rekening mee wordt gehouden, maar als dat niet het geval is, wordt de operator uitgevoerd zonder rekening te houden met de hint.

Het verwachte antwoord is dus de gegevens worden in de normale (SQL) modus geladen, de trigger wordt geactiveerd.

Volgens Oracle-documentatie (geciteerd uit 8.04):

Overtredingen van de beperkingen zorgen ervoor dat de instructie serieel wordt uitgevoerd, met behulp van het conventionele invoegpad, zonder waarschuwingen of foutmeldingen. Een uitzondering is de beperking voor instructies die meer dan één keer toegang hebben tot dezelfde tabel tijdens een transactie, wat foutmeldingen kan veroorzaken.
Als er bijvoorbeeld triggers of referentiële integriteit in de tabel aanwezig zijn, wordt de APPEND-hint genegeerd wanneer u direct-load INSERT (serieel of parallel) probeert te gebruiken, evenals de PARALLEL-hint of -clausule, indien aanwezig.

Wat gebeurt er als het volgende script wordt uitgevoerd?

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

  • Succesvol afgerond
  • Mislukt vanwege een syntaxisfout
  • Fout: autonome transactie is niet geldig
  • Fout gerelateerd aan het overschrijden van de maximale oproepnesting
  • Fout bij schending van buitenlandse sleutel
  • Fout gerelateerd aan sloten

BeantwoordenDe tabel en trigger zijn redelijk correct gemaakt en deze bewerking zou niet tot problemen moeten leiden. Ook autonome transacties in een trigger zijn toegestaan, anders zou loggen bijvoorbeeld niet mogelijk zijn.

Na het invoegen van de eerste rij zou een succesvolle activering van de trigger ervoor zorgen dat de tweede rij wordt ingevoegd, waardoor de trigger opnieuw wordt geactiveerd, een derde rij wordt ingevoegd, enzovoort, totdat de instructie mislukt omdat de maximale nesting van oproepen wordt overschreden. Er speelt echter nog een subtiel punt mee. Op het moment dat de trigger wordt uitgevoerd, is de commit nog niet voltooid voor het eerste ingevoegde record. Daarom probeert een trigger die wordt uitgevoerd in een autonome transactie een rij in de tabel in te voegen die verwijst naar een refererende sleutel naar een record dat nog niet is vastgelegd. Dit resulteert in een wachttijd (de autonome transactie wacht tot de hoofdtransactie zich vastlegt om te zien of deze gegevens kan invoegen) en tegelijkertijd wacht de hoofdtransactie tot de autonome transactie na de trigger verder werkt. Er treedt een impasse op en als gevolg daarvan wordt de autonome transactie geannuleerd vanwege redenen die verband houden met vergrendelingen.

Alleen geregistreerde gebruikers kunnen deelnemen aan het onderzoek. Inloggen, Alsjeblieft.

Het was moeilijk om?

  • Als twee vingers besloot ik meteen alles correct.

  • Niet echt, ik had het mis met een paar vragen.

  • Ik heb de helft correct opgelost.

  • Ik heb het antwoord twee keer geraden!

  • Ik zal in de reacties schrijven

14 gebruikers hebben gestemd. 10 gebruikers onthielden zich van stemming.

Bron: www.habr.com

Voeg een reactie