Treten Sie in die Fußstapfen von Highload++ Siberia 2019 – 8 Aufgaben auf Oracle

Hallo!

Am 24. und 25. Juni fand in Nowosibirsk die Konferenz „Highload++ Siberia 2019“ statt. Unsere Jungs waren auch dabei Prüfbericht „Oracle-Containerdatenbanken (CDB/PDB) und ihr praktischer Einsatz für die Softwareentwicklung“, eine Textversion veröffentlichen wir etwas später. Es war cool, danke Olegbunin für die Organisation sowie für alle, die gekommen sind.

Treten Sie in die Fußstapfen von Highload++ Siberia 2019 – 8 Aufgaben auf Oracle
In diesem Beitrag möchten wir mit Ihnen die Probleme teilen, die wir an unserem Stand hatten, damit Sie Ihr Oracle-Wissen testen können. Unterhalb des Ausschnitts befinden sich 8 Aufgaben, Antwortmöglichkeiten und Erklärungen.

Was ist der maximale Sequenzwert, den wir als Ergebnis der Ausführung des folgenden Skripts sehen werden?

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
  • Nein, es wird ein Fehler auftreten

AntwortLaut Oracle-Dokumentation (zitiert aus 8.1.6):
Innerhalb einer einzelnen SQL-Anweisung erhöht Oracle die Sequenz nur einmal pro Zeile. Wenn eine Anweisung mehr als einen Verweis auf NEXTVAL für eine Sequenz enthält, erhöht Oracle die Sequenz einmal und gibt für alle Vorkommen von NEXTVAL denselben Wert zurück. Wenn eine Anweisung Verweise sowohl auf CURRVAL als auch auf NEXTVAL enthält, erhöht Oracle die Sequenz und gibt für CURRVAL und NEXTVAL denselben Wert zurück, unabhängig von ihrer Reihenfolge innerhalb der Anweisung.

Somit kann die Der Maximalwert entspricht der Anzahl der Zeilen, also 5.

Wie viele Zeilen wird die Tabelle enthalten, wenn das folgende Skript ausgeführt wird?

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

AntwortLaut Oracle-Dokumentation (zitiert aus 11.2):

Bevor eine SQL-Anweisung ausgeführt wird, markiert Oracle einen impliziten Sicherungspunkt (für Sie nicht verfügbar). Wenn die Anweisung dann fehlschlägt, setzt Oracle sie automatisch zurück und gibt den entsprechenden Fehlercode an SQLCODE im SQLCA zurück. Wenn beispielsweise eine INSERT-Anweisung einen Fehler verursacht, indem sie versucht, einen doppelten Wert in einen eindeutigen Index einzufügen, wird die Anweisung zurückgesetzt.

Der Aufruf von HP vom Client aus wird ebenfalls als eine einzige Anweisung betrachtet und verarbeitet. Somit wird der erste HP-Aufruf erfolgreich abgeschlossen, nachdem drei Datensätze eingefügt wurden. der zweite HP-Aufruf endet mit einem Fehler und setzt den vierten Datensatz zurück, den er einfügen konnte; der dritte Anruf schlägt fehl, und es gibt drei Datensätze in der Tabelle.

Wie viele Zeilen wird die Tabelle enthalten, wenn das folgende Skript ausgeführt wird?

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

AntwortLaut Oracle-Dokumentation (zitiert aus 11.2):

Mit einer Check-Einschränkung können Sie eine Bedingung angeben, die jede Zeile in der Tabelle erfüllen muss. Um die Einschränkung zu erfüllen, muss jede Zeile in der Tabelle die Bedingung entweder TRUE oder unbekannt (aufgrund einer Null) machen. Wenn Oracle eine Check-Constraint-Bedingung für eine bestimmte Zeile auswertet, beziehen sich alle Spaltennamen in der Bedingung auf die Spaltenwerte in dieser Zeile.

Somit besteht der Wert Null die Prüfung und der anonyme Block wird erfolgreich ausgeführt, bis versucht wird, den Wert 3 einzufügen. Danach löscht der Fehlerbehandlungsblock die Ausnahme, es erfolgt kein Rollback und Es bleiben noch vier Zeilen in der Tabelle übrig mit den Werten 1, null, 2 und wieder null.

Welche Wertepaare nehmen im Block gleich viel Platz ein?

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 und X
  • B und Y
  • C und K
  • C und Z
  • K und Z
  • Ich und J
  • J und X
  • Alles das oben Genannte

AntwortHier finden Sie Auszüge aus der Dokumentation (12.1.0.2) zum Speichern verschiedener Datentypen in Oracle.

CHAR-Datentyp
Der Datentyp CHAR gibt eine Zeichenfolge fester Länge im Datenbankzeichensatz an. Sie geben den Datenbankzeichensatz an, wenn Sie Ihre Datenbank erstellen. Oracle stellt sicher, dass alle in einer CHAR-Spalte gespeicherten Werte die durch size in der ausgewählten Längensemantik angegebene Länge haben. Wenn Sie einen Wert einfügen, der kürzer als die Spaltenlänge ist, füllt Oracle den Wert mit Leerzeichen auf die Spaltenlänge auf.

VARCHAR2-Datentyp
Der Datentyp VARCHAR2 gibt eine Zeichenfolge variabler Länge im Datenbankzeichensatz an. Sie geben den Datenbankzeichensatz an, wenn Sie Ihre Datenbank erstellen. Oracle speichert einen Zeichenwert in einer VARCHAR2-Spalte genau so, wie Sie ihn angeben, ohne Leerzeichenauffüllung, vorausgesetzt, der Wert überschreitet nicht die Länge der Spalte.

NUMBER-Datentyp
Der Datentyp NUMBER speichert Null sowie positive und negative feste Zahlen mit absoluten Werten von 1.0 x 10-130 bis 1.0 x 10126, jedoch nicht einschließlich. Wenn Sie einen arithmetischen Ausdruck angeben, dessen Wert einen absoluten Wert größer oder gleich hat 1.0 x 10126, dann gibt Oracle einen Fehler zurück. Jeder NUMBER-Wert erfordert 1 bis 22 Bytes. Unter Berücksichtigung dessen kann die Spaltengröße in Bytes für einen bestimmten numerischen Datenwert NUMBER(p), wobei p die Genauigkeit eines bestimmten Werts ist, mithilfe der folgenden Formel berechnet werden: RUND((Länge(p)+s)/2))+1 Dabei ist s gleich Null, wenn die Zahl positiv ist, und s gleich 1, wenn die Zahl negativ ist.

Nehmen wir außerdem einen Auszug aus der Dokumentation zum Speichern von Nullwerten.

Eine Null ist das Fehlen eines Werts in einer Spalte. Nullen weisen auf fehlende, unbekannte oder nicht anwendbare Daten hin. Nullwerte werden in der Datenbank gespeichert, wenn sie zwischen Spalten mit Datenwerten liegen. In diesen Fällen benötigen sie 1 Byte, um die Länge der Spalte (Null) zu speichern. Nachfolgende Nullen in einer Zeile erfordern keinen Speicher, da ein neuer Zeilenkopf signalisiert, dass die verbleibenden Spalten in der vorherigen Zeile Nullen sind. Wenn beispielsweise die letzten drei Spalten einer Tabelle null sind, werden für diese Spalten keine Daten gespeichert.

Basierend auf diesen Daten bauen wir Argumente auf. Wir gehen davon aus, dass die Datenbank die AL32UTF8-Kodierung verwendet. Bei dieser Kodierung belegen russische Buchstaben 2 Bytes.

1) A und X, der Wert von Feld a „Y“ benötigt 1 Byte, der Wert von Feld x „D“ benötigt 2 Bytes
2) B und Y, „Vasya“ in b, der Wert wird mit Leerzeichen bis zu 10 Zeichen aufgefüllt und benötigt 14 Bytes, „Vasya“ in d benötigt 8 Bytes.
3) C und K. Beide Felder haben den Wert NULL, nach ihnen gibt es signifikante Felder, sie belegen also 1 Byte.
4) C und Z. Beide Felder haben den Wert NULL, aber Feld Z ist das letzte in der Tabelle und belegt daher keinen Platz (0 Bytes). Feld C belegt 1 Byte.
5) K und Z. Ähnlich wie im vorherigen Fall. Der Wert im K-Feld belegt 1 Byte, in Z – 0.
6) I und J. Laut Dokumentation belegen beide Werte 2 Bytes. Wir berechnen die Länge mit der Formel aus der Dokumentation: Round( (1 + 0)/2) +1 = 1 + 1 = 2.
7) J und X. Der Wert im J-Feld benötigt 2 Bytes, der Wert im X-Feld benötigt 2 Bytes.

Insgesamt sind die richtigen Optionen: C und K, I und J, J und X.

Wie hoch wird ungefähr der Clustering-Faktor des T_I-Index sein?

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

  • Ungefähr Zehner
  • Ungefähr Hunderte
  • Ungefähr Tausende
  • Ungefähr Zehntausende

AntwortLaut Oracle-Dokumentation (zitiert aus 12.1):

Bei einem B-Tree-Index misst der Index-Clustering-Faktor die physische Gruppierung von Zeilen im Verhältnis zu einem Indexwert.

Der Index-Clustering-Faktor hilft dem Optimierer bei der Entscheidung, ob ein Index-Scan oder ein vollständiger Tabellen-Scan für bestimmte Abfragen effizienter ist. Ein niedriger Clustering-Faktor weist auf einen effizienten Index-Scan hin.

Ein Clustering-Faktor, der nahe an der Anzahl der Blöcke in einer Tabelle liegt, zeigt an, dass die Zeilen in den Tabellenblöcken physisch nach dem Indexschlüssel geordnet sind. Wenn die Datenbank einen vollständigen Tabellenscan durchführt, tendiert die Datenbank dazu, die Zeilen abzurufen, wenn sie nach dem Indexschlüssel sortiert auf der Festplatte gespeichert sind. Ein Clustering-Faktor, der nahe an der Anzahl der Zeilen liegt, weist darauf hin, dass die Zeilen im Verhältnis zum Indexschlüssel zufällig über die Datenbankblöcke verteilt sind. Wenn die Datenbank einen vollständigen Tabellenscan durchführt, ruft die Datenbank die Zeilen in keiner nach diesem Indexschlüssel sortierten Reihenfolge ab.

In diesem Fall sind die Daten ideal sortiert, sodass der Clustering-Faktor gleich oder nahe der Anzahl der belegten Blöcke in der Tabelle ist. Bei einer Standardblockgröße von 8 Kilobyte können Sie davon ausgehen, dass etwa tausend schmale Zahlenwerte in einen Block passen, sodass die Anzahl der Blöcke und damit der Clustering-Faktor gleich sind etwa Zehner.

Bei welchen Werten von N wird das folgende Skript in einer regulären Datenbank mit Standardeinstellungen erfolgreich ausgeführt?

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

AntwortLaut Oracle-Dokumentation (zitiert aus 11.2):

Grenzwerte für logische Datenbanken

Artikel
Art des Limits
Grenzwert

Indizes
Gesamtgröße der indizierten Spalte
75 % der Datenbankblockgröße abzüglich etwas Overhead

Daher sollte die Gesamtgröße der indizierten Spalten 6 KB nicht überschreiten. Was als nächstes passiert, hängt von der gewählten Basiskodierung ab. Bei der AL32UTF8-Kodierung kann ein Zeichen maximal 4 Byte belegen, sodass im schlimmsten Fall 6 Kilobyte für etwa 1500 Zeichen passen. Daher verbietet Oracle die Indexerstellung bei N = 400 (wenn die Schlüssellänge im ungünstigsten Fall 1600 Zeichen * 4 Bytes + Zeilen-ID-Länge beträgt), während bei N = 200 (oder weniger) Das Erstellen des Index funktioniert problemlos.

Der INSERT-Operator mit dem APPEND-Hinweis dient zum Laden von Daten im Direktmodus. Was passiert, wenn es auf die Tabelle angewendet wird, an der der Trigger hängt?

  • Die Daten werden im Direktmodus geladen, der Trigger funktioniert wie erwartet
  • Die Daten werden im Direktmodus geladen, der Trigger wird jedoch nicht ausgeführt
  • Die Daten werden im herkömmlichen Modus geladen, der Trigger funktioniert wie gewünscht
  • Die Daten werden im herkömmlichen Modus geladen, der Trigger wird jedoch nicht ausgeführt
  • Die Daten werden nicht geladen, es wird ein Fehler aufgezeichnet

AntwortIm Grunde ist das eher eine Frage der Logik. Um die richtige Antwort zu finden, würde ich das folgende Argumentationsmodell vorschlagen:

  1. Das Einfügen im Direktmodus erfolgt durch direkte Bildung eines Datenblocks unter Umgehung der SQL-Engine, was eine hohe Geschwindigkeit gewährleistet. Daher ist es sehr schwierig, wenn nicht sogar unmöglich, die Ausführung des Auslösers sicherzustellen, und dies hat keinen Sinn, da es das Einfügen immer noch radikal verlangsamt.
  2. Wenn der Trigger nicht ausgeführt wird, führt dies dazu, dass bei gleichen Daten in der Tabelle der Status der gesamten Datenbank (andere Tabellen) vom Modus abhängt, in dem diese Daten eingefügt wurden. Dies zerstört offensichtlich die Datenintegrität und kann nicht als Lösung in der Produktion angewendet werden.
  3. Die Unfähigkeit, den angeforderten Vorgang auszuführen, wird im Allgemeinen als Fehler behandelt. Hier sollten wir jedoch bedenken, dass APPEND ein Hinweis ist und die allgemeine Logik von Hinweisen darin besteht, dass sie nach Möglichkeit berücksichtigt werden. Wenn nicht, wird der Operator ausgeführt, ohne den Hinweis zu berücksichtigen.

Die erwartete Antwort lautet also Die Daten werden im normalen (SQL-)Modus geladen, der Trigger wird ausgelöst.

Laut Oracle-Dokumentation (zitiert aus 8.04):

Verstöße gegen die Einschränkungen führen dazu, dass die Anweisung seriell unter Verwendung des herkömmlichen Einfügepfads ohne Warnungen oder Fehlermeldungen ausgeführt wird. Eine Ausnahme bildet die Beschränkung, dass Anweisungen mehrmals in einer Transaktion auf dieselbe Tabelle zugreifen, was zu Fehlermeldungen führen kann.
Wenn beispielsweise Trigger oder referenzielle Integrität in der Tabelle vorhanden sind, wird der APPEND-Hinweis ignoriert, wenn Sie versuchen, INSERT (seriell oder parallel) zum direkten Laden zu verwenden, sowie der PARALLEL-Hinweis oder die PARALLEL-Klausel, falls vorhanden.

Was passiert, wenn das folgende Skript ausgeführt wird?

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

  • Erfolgreiche Fertigstellung
  • Fehler aufgrund eines Syntaxfehlers
  • Fehler: Autonome Transaktion ist ungültig
  • Fehler im Zusammenhang mit der Überschreitung der maximalen Anrufverschachtelung
  • Fehler bei Fremdschlüsselverletzung
  • Fehler im Zusammenhang mit Sperren

AntwortDie Tabelle und der Trigger werden völlig korrekt erstellt und dieser Vorgang sollte nicht zu Problemen führen. Auch autonome Transaktionen in einem Trigger sind erlaubt, da sonst beispielsweise eine Protokollierung nicht möglich wäre.

Nach dem Einfügen der ersten Zeile würde eine erfolgreiche Auslösung des Triggers dazu führen, dass die zweite Zeile eingefügt wird, wodurch der Trigger erneut ausgelöst wird, eine dritte Zeile eingefügt wird usw., bis die Anweisung aufgrund der Überschreitung der maximalen Verschachtelung von Aufrufen fehlschlägt. Es kommt jedoch noch ein weiterer subtiler Punkt ins Spiel. Zum Zeitpunkt der Ausführung des Triggers ist der Commit für den ersten eingefügten Datensatz noch nicht abgeschlossen. Daher versucht ein in einer autonomen Transaktion ausgeführter Trigger, eine Zeile in die Tabelle einzufügen, die auf einen Fremdschlüssel für einen Datensatz verweist, der noch nicht festgeschrieben wurde. Dies führt zu einer Wartezeit (die autonome Transaktion wartet auf den Commit der Haupttransaktion, um zu sehen, ob sie Daten einfügen kann) und gleichzeitig wartet die Haupttransaktion darauf, dass die autonome Transaktion nach dem Auslöser weiterarbeitet. Es kommt zu einem Deadlock und infolgedessen wird die autonome Transaktion aus Gründen im Zusammenhang mit Sperren abgebrochen.

An der Umfrage können nur registrierte Benutzer teilnehmen. Einloggenbitte.

Es war schwierig?

  • Wie zwei Finger habe ich sofort alles richtig entschieden.

  • Nicht wirklich, ich habe mich in ein paar Fragen geirrt.

  • Ich habe die Hälfte davon richtig gelöst.

  • Ich habe die Antwort zweimal erraten!

  • Ich schreibe in die Kommentare

14 Benutzer haben abgestimmt. 10 Benutzer enthielten sich der Stimme.

Source: habr.com

Kommentar hinzufügen