Kapitel 4. CockroachDB SQL

Diese Arbeit wurde mithilfe von KI übersetzt. Wir freuen uns über dein Feedback und deine Kommentare: translation-feedback@oreilly.com

Die Sprache von CockroachDB ist SQL. Es gibt zwar einige Befehlszeilen-Dienstprogramme, aber alle Interaktionen zwischen einer Anwendung und der Datenbank werden über SQL-Befehle abgewickelt.

SQL ist eine reichhaltige Sprache mit einer langen Geschichte - wir haben in Kapitel 1 bereits einige dieser Geschichte angesprochen. Eine vollständige Definition aller SQL-Funktionen würde ein eigenes Buch erfordern und wäre fast sofort veraltet, da sich die SQL-Sprache mit jeder neuen Version weiterentwickelt.

Dieses Kapitel soll dir daher einen umfassenden Überblick über die in CockroachDB verwendete SQL-Sprache geben, ohne den Anspruch zu erheben, eine vollständige Referenz zu sein. Wir werden einen aufgabenorientierten Ansatz für SQL wählen und die häufigsten Aufgaben der SQL-Sprache mit besonderem Bezug auf die Besonderheiten der CockroachDB-SQL-Implementierung behandeln.

Wie wir in Kapitel 1 beschrieben haben, ist SQL eine deklarative Sprache. SQL-Anweisungen stellen logische Anfragen für Abfragen und Datenmanipulationsoperationen dar, ohne zu spezifizieren, wie die Datenbank diese Anfragen umsetzen soll.

Eine vollständige Referenz für die CockroachDB-SQL-Sprache findest du in der CockroachDB-Dokumentation. Eine umfassendere Übersicht über die SQL-Sprache findest du im O'Reilly-Buch SQL in a Nutshell.

Einige der Beispiele in diesem Kapitel verwenden den MovR-Beispieldatensatz in diesem Kapitel, um verschiedene Funktionen der SQL-Sprache zu veranschaulichen. Wir haben in Kapitel 2 gezeigt, wie man Beispieldaten installiert.

SQL-Sprachkompatibilität

CockroachDB ist weitgehend kompatibel mit , der PostgreSQL-Implementierung des SQL:2016-Standards. Der SQL:2016-Standard enthält eine Reihe unabhängiger Module, und keine große Datenbank implementiert alle Standards. Die PostgreSQL-Implementierung von SQL ist jedoch so nah am "Standard", wie es ihn in der Datenbankgemeinschaft gibt.

CockroachDB unterscheidet sich in einigen Bereichen von PostgreSQL:

  • CockroachDB unterstützt derzeit keine Stored Procedures, Events oder Trigger. In PostgreSQL werden diese Stored Procedures in der Sprache PL/pgSQL geschrieben und ermöglichen die Ausführung von Programmlogik innerhalb des Datenbankservers, entweder bei Bedarf oder als Reaktion auf ein auslösendes Ereignis.

  • CockroachDB unterstützt derzeit keine benutzerdefinierten Funktionen.

  • CockroachDB unterstützt keine PostgreSQL XML-Funktionen.

  • CockroachDB unterstützt keine PostgreSQL-Volltextindizes und -funktionen.

Daten mit SELECT abfragen

Obwohl wir Tabellen erstellen und auffüllen müssen, bevor wir sie abfragen können, ist es logisch, mit der SELECT Anweisung zu beginnen, da viele Funktionen der SELECT Anweisung auch in anderen Arten von SQL vorkommen - zum Beispiel Unterabfragen in UPDATE- und für Datenwissenschaftler und Analysten ist die SELECT Anweisung oft die einzige SQL-Anweisung, die sie jemals lernen müssen.

Die Anweisung SELECT (Abbildung 4-1) ist das Arbeitspferd der relationalen Abfragen und hat eine komplexe und umfangreiche Syntax. Die Anweisung CockroachDB SELECT implementiert die Standardfunktionen der Standardanweisung SELECT mit einigen wenigen CockroachDB-spezifischen Funktionen.

crdb 0401
Abbildung 4-1. SELECT Anweisung

In den folgenden Abschnitten werden wir die wichtigsten Elemente der Anweisung SELECT sowie die Funktionen und Operatoren, die darin enthalten sein können, untersuchen.

Die SELECT-Liste

Eine einfache SQL-Anweisung besteht aus nichts anderem als einer SELECT Anweisung zusammen mit skalaren Ausdrücken (z.B. Ausdrücke, die einen einzelnen Wert zurückgeben). Zum Beispiel:

SELECT CONCAT('Hello from CockroachDB at ',
              CAST (NOW() as STRING)) as hello;

Die Liste SELECT enthält eine kommagetrennte Liste von Ausdrücken, die Kombinationen von Konstanten, Funktionen und Operatoren enthalten können. Die CockroachDB-SQL-Sprache unterstützt alle bekannten SQL-Operatoren. Eine vollständige Liste der Funktionen und Operatoren findest du in der CockroachDB-Dokumentation.

Die FROM-Klausel

Die FROM Klausel ist die primäre Methode, um Tabellendaten mit der SELECT Anweisung zu verknüpfen. In ihrer einfachsten Ausprägung können alle Zeilen und Spalten einer Tabelle über einen Full Table Scan abgerufen werden:

SELECT * FROM rides;

Tabellennamen können mit der AS Klausel oder einfach durch einen Alias nach dem Tabellennamen verknüpft werden. Dieser Alias kann dann überall in der Abfrage verwendet werden, um auf die Tabelle zu verweisen. Auch Spaltennamen können als Alias verwendet werden. Die folgenden Namen sind zum Beispiel alle gleichwertig:

SELECT name FROM users;
SELECT u.name FROM users u;
SELECT users.name FROM users;
SELECT users.name AS user_name FROM users;
SELECT u.name FROM users AS u;

JOINS

Mit Joins können die Ergebnisse aus zwei oder mehr Tabellen auf der Grundlage einiger gemeinsamer Spaltenwerte zusammengeführt werden.

Die INNER JOIN ist die Standardoperation JOIN. Bei dieser Verknüpfung werden Zeilen aus einer Tabelle mit Zeilen aus einer anderen Tabelle auf der Grundlage gemeinsamer ("Schlüssel") Werte verbunden. Zeilen, die in beiden Tabellen nicht übereinstimmen, werden nicht in die Ergebnisse aufgenommen. Die folgende Abfrage verknüpft zum Beispiel Fahrzeug- und Fahrtinformationen in der Datenbank movr:

SELECT v.id,v.ext,r.start_time, r.start_address
  FROM vehicles v
  INNER JOIN rides r
    ON (r.vehicle_id=v.id);

Beachte, dass ein Fahrzeug, das nicht an einer Fahrt beteiligt war, nicht in die Ergebnismenge aufgenommen wird.

Die ON Klausel gibt die Bedingungen an, die die beiden Tabellen verbinden - in der vorherigen Abfrage wurden die Spalten vehicle_id in der Tabelle rider mit der Spalte id in der Tabelle vehicles abgeglichen. Wenn die JOIN in beiden Tabellen eine gleichnamige Spalte enthält, bietet die USING Klausel eine praktische Abkürzung. Hier verbinden wir users und user_ride_counts über die gemeinsame Spalte name:1

SELECT *
  FROM users u
  JOIN user_ride_counts urc
 USING (name);

Die OUTER JOIN ermöglicht es, dass Zeilen auch dann in aufgenommen werden, wenn sie in der anderen Tabelle keine Übereinstimmung haben. Zeilen, die in der Tabelle OUTER JOIN nicht gefunden werden, werden durch die Werte von NULL dargestellt. LEFT und RIGHT bestimmen, welche Tabelle fehlende Werte haben kann. Die folgende Abfrage gibt zum Beispiel alle Benutzer in der Tabelle users aus, auch wenn einige nicht mit einem Promo-Code verbunden sind:

SELECT u.name , upc.code
  FROM users u
  LEFT OUTER JOIN user_promo_codes upc
    ON (u.id=upc.user_id);

Die RIGHT OUTER JOIN kehrt den Standard (LEFT) OUTER JOIN um. Diese Abfrage ist also identisch mit der vorherigen Abfrage, weil die Tabelle users jetzt die "richtige" Tabelle in der Verknüpfung ist:

SELECT DISTINCT u.name , upc.code
  FROM user_promo_codes upc
  RIGHT OUTER JOIN users u
    ON (u.id=upc.user_id);

Anti-Joins

Oft ist es erforderlich, alle Zeilen aus einer Tabelle auszuwählen, für die es keine passende Zeile in einer anderen Ergebnismenge gibt. Dies wird als Anti-Join bezeichnet, und obwohl es keine SQL-Syntax für dieses Konzept gibt, wird es in der Regel mit einer Unterabfrage und der Klausel IN oder EXISTS implementiert. Das folgende Beispiel veranschaulicht einen Anti-Join mit den Operatoren EXISTS und IN.

Jedes Beispiel wählt Nutzer aus, die nicht gleichzeitig Arbeitnehmer sind:

SELECT *
  FROM users
 WHERE id NOT IN
       (SELECT id FROM employees);

Diese Abfrage liefert dieselben Ergebnisse, aber mit einer korrelierten Unterabfrage (wir werden Unterabfragen in einem späteren Abschnitt ausführlicher besprechen ):

SELECT *
   FROM users u
  WHERE NOT EXISTS
        (SELECT id
           FROM employees e
          WHERE e.id=u.id);

Kreuzfugen

CROSS JOIN bedeutet, dass jede Zeile in der linken Tabelle mit jeder Zeile in der rechten Tabelle verknüpft werden soll. Normalerweise ist das ein Rezept für eine Katastrophe, es sei denn, eine der Tabellen hat nur eine Zeile oder ist eine lateral korrelierte Unterabfrage (siehe "Korrelierte Unterabfrage").

Operationen einstellen

SQL implementiert eine Reihe von Operationen, die direkt mit Ergebnismengen arbeiten. Diese Operationen, die zusammen als "Mengenoperationen" bezeichnet werden, ermöglichen es, Ergebnismengen zu verketten, zu subtrahieren oder zu überlagern.

Die gebräuchlichste dieser Operationen ist der UNION Operator, der die Summe von zwei Ergebnismengen liefert. Standardmäßig werden Duplikate in jeder Ergebnismenge eliminiert. Im Gegensatz dazu gibt die Operation UNION ALL die Summe der beiden Ergebnismengen zurück, einschließlich aller Duplikate. Das folgende Beispiel gibt eine Liste von Kunden und Mitarbeitern zurück. Mitarbeiter, die auch Kunden sind, werden nur einmal aufgeführt:

SELECT name, address
  FROM customers
 UNION
SELECT name,address
  FROM employees;

INTERSECT gibt die Zeilen zurück, die in beiden Ergebnismengen enthalten sind. Diese Abfrage liefert Kunden, die auch Mitarbeiter sind:

SELECT name, address
  FROM customers
 INTERSECT
SELECT name,address
  FROM employees;

EXCEPT gibt Zeilen in der ersten Ergebnismenge zurück, die in der zweiten nicht vorhanden sind. Diese Abfrage gibt Kunden zurück, die nicht gleichzeitig Mitarbeiter sind:

SELECT name, address
  FROM customers
 EXCEPT
SELECT name,address
  FROM employees;

Alle Mengenoperationen setzen voraus, dass die Komponentenabfragen die gleiche Anzahl von Spalten zurückgeben und dass diese Spalten einen kompatiblen Datentyp haben.

Gruppe Operationen

Mit Hilfe von Aggregatoperationen können zusammenfassende Informationen erstellt werden, in der Regel nach Gruppierung von Zeilen. Zeilen können mit dem GROUP BY Operator gruppiert werden. In diesem Fall darf die Auswahlliste nur aus Spalten bestehen, die in der GROUP BY Klausel und den Aggregatfunktionen enthalten sind.

Die gängigsten Aggregatfunktionen sind in Tabelle 4-1 aufgeführt.

Tabelle 4-1. Aggregat-Funktionen

AVG

Berechne den Durchschnittswert für die Gruppe.

COUNT

Gibt die Anzahl der Zeilen in der Gruppe zurück.

MAX

Gib den maximalen Wert in der Gruppe zurück.

MIN

Gibt den Mindestwert in der Gruppe zurück.

STDDEV

Gib die Standardabweichung für die Gruppe zurück.

SUM

Gibt die Summe aller Werte für die Gruppe zurück.

Das folgende Beispiel generiert zusammenfassende Fahrteninformationen für jede Stadt:

SELECT u.city,SUM(urc.rides),AVG(urc.rides),max(urc.rides)
  FROM users u
  JOIN user_ride_counts urc
 USING (name)
 GROUP BY u.city;

Unterabfragen

Eine Subquery ist eine SELECT Anweisung, die innerhalb einer anderen SQL-Anweisung steht. Eine solche "verschachtelte" SELECT Anweisung kann in einer Vielzahl von SQL-Kontexten verwendet werden, einschließlich SELECT, DELETE, UPDATE und INSERT Anweisungen.

Die folgende Anweisung verwendet eine Unterabfrage, um die Anzahl der Fahrten zu zählen, die die maximale Fahrtdauer teilen:

SELECT COUNT(*) FROM rides
 WHERE (end_time-start_time)=
 	(SELECT MAX(end_time-start_time) FROM rides );

Unterabfragen können auch in der FROM Klausel verwendet werden, wo immer eine Tabellen- oder View-Definition erscheinen könnte. Diese Abfrage erzeugt ein Ergebnis, das jede Fahrt mit der durchschnittlichen Fahrtdauer für die Stadt vergleicht:

SELECT id, city,(end_time-start_time) ride_duration, avg_ride_duration
  FROM rides
  JOIN (SELECT city,
               AVG(end_time-start_time) avg_ride_duration
	   FROM rides
	  GROUP BY city)
 USING(city) ;

Korrelierte Unterabfrage

Eine korrelierte Subquery ist eine , bei der sich die Subquery auf Werte in der übergeordneten Abfrage oder Operation bezieht. Die Subquery gibt für jede Zeile in der übergeordneten Ergebnismenge ein anderes Ergebnis zurück. Ein Beispiel für eine korrelierte Subquery haben wir weiter oben im Kapitel gesehen, als wir einen "Anti-Join" durchgeführt haben.

SELECT *
   FROM users u
  WHERE NOT EXISTS
        (SELECT id
           FROM employees e
          WHERE e.id=u.id);

Unterabfragen können oft verwendet werden, um eine Operation durchzuführen, die funktional einem Join entspricht. In vielen Fällen wandelt der Abfrageoptimierer diese Anweisungen in Joins um, um den Optimierungsprozess zu vereinfachen.

Seitliche Unterabfrage

Wenn eine Subquery in einer Verknüpfung verwendet wird, zeigt das LATERAL Schlüsselwort an, dass die Subquery auf Spalten zugreifen kann, die in vorangegangenen FROM Tabellenausdrücken erzeugt wurden. In der folgenden Abfrage erlaubt das Schlüsselwort LATERAL der Subquery zum Beispiel den Zugriff auf Spalten aus der Tabelle users:

  SELECT name, address, start_time
   FROM users CROSS JOIN
        LATERAL (SELECT *
                   FROM rides
                  WHERE rides.start_address = users.address ) r;

Dieses Beispiel ist etwas konstruiert, und wir könnten natürlich eine einfache JOIN konstruieren, die diese Abfrage natürlicher ausführt. Wo LATERAL Joins wirklich glänzen, ist, wenn Unterabfragen auf berechnete Spalten in anderen Unterabfragen innerhalb einer FROM Klausel zugreifen können. Andy Woods' CockroachDB-Blogpost beschreibt ein ernsthafteres Beispiel für laterale Unterabfragen.

Die WHERE-Klausel

Die WHERE Klausel ist gemeinsam mit SELECT, UPDATE und DELETE Anweisungen. Sie gibt eine Reihe von logischen Bedingungen an, die für alle Zeilen, die von der betreffenden SQL-Anweisung zurückgegeben oder verarbeitet werden sollen, true ergeben müssen.

Gemeinsame Tabellenausdrücke

SQL-Anweisungen mit vielen Unterabfragen können schwer zu lesen und zu pflegen sein, besonders wenn dieselbe Unterabfrage in mehreren Kontexten innerhalb der Abfrage benötigt wird. Aus diesem Grund unterstützt SQL Common Table Expressions mit der WITH Klausel. Abbildung 4-2 zeigt die Syntax eines Common Table Expression.

Common Table Expression
Abbildung 4-2. Gemeinsamer Tabellenausdruck

In seiner einfachsten Form ist ein Common Table Expression einfach ein benannter Abfrageblock, der überall dort angewendet werden kann, wo ein Tabellenausdruck verwendet werden kann. In diesem Beispiel verwenden wir die WITH Klausel, um einen Common Table Expression riderRevenue zu erstellen, auf den wir dann in der FROM Klausel der Hauptabfrage verweisen:

WITH riderRevenue AS (
	  SELECT u.id, SUM(r.revenue) AS sumRevenue
	    FROM rides r JOIN "users" u
	    ON (r.rider_id=u.id)
	   GROUP BY u.id)
SELECT * FROM "users" u2
         JOIN riderRevenue rr USING (id)
 ORDER BY sumrevenue DESC;

Mit der RECURSIVE Klausel kann der Common Table Expression auf sich selbst verweisen, so dass eine Abfrage eine beliebig große (oder sogar unendliche) Menge von Ergebnissen liefern kann. Wenn zum Beispiel die Tabelle employees eine Spalte manager_id enthält, die auf die Zeile des Managers in derselben Tabelle verweist, könnten wir eine Hierarchie von Angestellten und Managern wie folgt ausgeben:

WITH RECURSIVE employeeMgr AS (
  SELECT id,manager_id, name , NULL AS manager_name, 1 AS level
    FROM employees managers
   WHERE manager_id IS NULL
  UNION ALL
  SELECT subordinates.id,subordinates.manager_id,
         subordinates.name, managers.name ,managers.LEVEL+1
    FROM employeeMgr managers
    JOIN employees subordinates
      ON (subordinates.manager_id=managers.id)
)
SELECT * FROM employeeMgr;

Die MATERIALIZED Klausel zwingt CockroachDB dazu, die Ergebnisse der Common Table Expression als temporäre Tabelle zu speichern, anstatt sie bei jedem Auftreten neu auszuführen. Dies kann nützlich sein, wenn die Common Table Expression mehrfach in der Abfrage referenziert wird.

ORDER BY

Mit der ORDER BY Klausel können die Abfrageergebnisse in sortierter Reihenfolge zurückgegeben werden. Abbildung 4-3 zeigt die ORDER BY Syntax.

OrderBy
Abbildung 4-3. ORDER BY

In der einfachsten Form nimmt ORDER BY einen oder mehrere Spaltenausdrücke oder Spaltennummern aus der Liste SELECT.

In diesem Beispiel sortieren wir nach Spaltennummern:

SELECT city,start_time, (end_time-start_time) duration
   FROM rides r
  ORDER BY 1,3 DESC;

Und in diesem Fall durch Spaltenausdrücke:

SELECT city,start_time, (end_time-start_time) duration
   FROM rides r
  ORDER BY city,(end_time-start_time)  DESC;

Du kannst auch nach einem Index sortieren. Im folgenden Beispiel werden die Zeilen nach city und start_time sortiert, da dies die im Index angegebenen Spalten sind:

CREATE INDEX rides_start_time ON rides (city ,start_time);

SELECT city,start_time, (end_time-start_time) duration
  FROM rides
 ORDER BY INDEX rides@rides_start_time;

Die Verwendung von ORDER BY INDEX garantiert, dass der Index verwendet wird, um die Zeilen direkt in sortierter Reihenfolge zurückzugeben, anstatt eine Sortieroperation an den Zeilen durchzuführen, nachdem sie abgerufen wurden. In Kapitel 8 findest du weitere Hinweise zur Optimierung von Anweisungen, die einen ORDER BY enthalten.

Fensterfunktionen

Fensterfunktionen sind Funktionen, die auf einer Teilmenge - einem "Fenster" - der gesamten Ergebnismenge arbeiten. Abbildung 4-4 zeigt die Syntax einer Fensterfunktion.

WindowFunction
Abbildung 4-4. Syntax der Fensterfunktion

PARTITION BY und ORDER BY erstellen eine Art "virtuelle Tabelle", mit der die Funktion arbeitet. Diese Abfrage listet zum Beispiel die 10 umsatzstärksten Fahrten auf, wobei der prozentuale Anteil am Gesamtumsatz und der Umsatz der Stadt angezeigt wird:

SELECT city, r.start_time ,revenue,
       revenue*100/SUM(revenue) OVER () AS pct_total_revenue,
       revenue*100/SUM(revenue) OVER (PARTITION BY city) AS pct_city_revenue
  FROM rides r
 ORDER BY 5 DESC
 LIMIT 10;

Es gibt einige Aggregationsfunktionen die spezifisch für Fensterfunktionen sind. RANK() ordnet die vorhandene Zeile innerhalb des jeweiligen Fensters ein und DENSE_RANK() tut dasselbe, lässt aber keine "fehlenden" Ränge zu. LEAD und LAG ermöglichen den Zugriff auf Funktionen in benachbarten Partitionen.

Diese Abfrage liefert zum Beispiel die Top 10 Fahrten, wobei der Gesamtrang jeder Fahrt und der Rang innerhalb der Stadt angezeigt wird:

SELECT city, r.start_time ,revenue,
       RANK() OVER
           (ORDER BY revenue DESC) AS total_revenue_rank,
       RANK() OVER
            (PARTITION BY city ORDER BY revenue DESC) AS city_revenue_rank
  FROM rides r
 ORDER BY revenue DESC
 LIMIT 10;

Andere SELECT-Klauseln

Die LIMIT Klausel begrenzt die Anzahl der Zeilen, die von einer SELECT zurückgegeben werden, während die OFFSET Klausel eine bestimmte Anzahl von Zeilen "vorspringt". Dies kann praktisch sein, um durch eine Ergebnismenge zu paginieren, obwohl es fast immer effizienter ist, eine Filterbedingung zu verwenden, um zur nächsten Teilmenge der Ergebnisse zu navigieren, da sonst bei jeder Anfrage eine zunehmende Anzahl von Zeilen erneut gelesen und verworfen werden muss.

CockroachDB-Arrays

Mit dem Typ ARRAY kann eine Spalte als eindimensionales Array von Elementen definiert werden, die alle einen gemeinsamen Datentyp haben. Wir werden im nächsten Kapitel über Arrays im Zusammenhang mit der Datenmodellierung sprechen. Obwohl sie nützlich sein können, sind sie streng genommen ein Verstoß gegen das relationale Modell und sollten mit Vorsicht verwendet werden.

Eine ARRAY -Variable wird definiert, indem "[]" oder das Wort "ARRAY" an den Datentyp einer Spalte angehängt wird. Zum Beispiel:

CREATE TABLE arrayTable (arrayColumn STRING[]);
CREATE TABLE anotherTable (integerArray INT ARRAY);

Mit der Funktion ARRAY können wir mehrere Artikel in die ARRAY einfügen:

INSERT INTO arrayTable VALUES (ARRAY['sky', 'road', 'car']);
SELECT * FROM arrayTable;

   arraycolumn
------------------
  {sky,road,car}

Wir können auf ein einzelnes Element eines Arrays mit der folgenden bekannten Notation für Arrayelemente zugreifen:

SELECT arrayColumn[2] FROM arrayTable;
  arraycolumn
---------------
  road

Der @> Operator kann verwendet werden, um Arrays zu finden, die ein oder mehrere Elemente enthalten:

SELECT * FROM arrayTable WHERE arrayColumn @>ARRAY['road'];
   arraycolumn
------------------
  {sky,road,car}

Wir können mit der Funktion array_append Elemente zu einem bestehenden Array hinzufügen und mit array_remove Elemente entfernen:

UPDATE  arrayTable
   SET arrayColumn=array_append(arrayColumn,'cat')
  WHERE arrayColumn @>ARRAY['car']
 RETURNING arrayColumn;

     arraycolumn
----------------------
  {sky,road,car,cat}

 UPDATE  arrayTable
   SET arrayColumn=array_remove(arrayColumn,'car')
  WHERE arrayColumn @>ARRAY['car']
  RETURNING arrayColumn;

   arraycolumn
------------------
  {sky,road,cat}

Schließlich wandelt die Funktion unnest ein Array in ein tabellarisches Ergebnis um - eine Zeile für jedes Element des Arrays. Damit kann der Inhalt eines Arrays mit Daten in relationaler Form an anderer Stelle in der Datenbank "verknüpft" werden. Ein Beispiel dafür zeigen wir im nächsten Kapitel:

SELECT unnest(arrayColumn)
  FROM ((("queries", "arrays", startref="qarys")))arrayTable;

  unnest
----------
  sky
  road
  cat

Arbeiten mit JSON

Der Datentyp JSONB ermöglicht es uns, JSON-Dokumente in einer Spalte zu speichern, und CockroachDB bietet Operatoren und Funktionen, die uns bei der Arbeit mit JSON helfen.

Für diese Beispiele haben wir eine Tabelle mit einem Primärschlüssel customerid und allen Daten in einer JSONB Spalte, jsondata, erstellt. Mit der Funktion jsonb_pretty können wir das JSON in einer schön formatierten Form abrufen:

 SELECT jsonb_pretty(jsondata)
   FROM customersjson WHERE customerid=1;

                     jsonb_pretty
------------------------------------------------------
  {
      "Address": "1913 Hanoi Way",
      "City": "Sasebo",
      "Country": "Japan",
      "District": "Nagasaki",
      "FirstName": "MARY",
      "LastName": "Smith",
      "Phone": 886780309,
      "_id": "5a0518aa5a4e1c8bf9a53761",
      "dateOfBirth": "1982-02-20T13:00:00.000Z",
      "dob": "1982-02-20T13:00:00.000Z",
      "randValue": 0.47025846594884335,
      "views": [
          {
              "filmId": 611,
              "title": "MUSKETEERS WAIT",
              "viewDate": "2013-03-02T05:26:17.645Z"
          },
          {
              "filmId": 308,
              "title": "FERRIS MOTHER",
              "viewDate": "2015-07-05T20:06:58.891Z"
          },
          {
              "filmId": 159,
              "title": "CLOSER BANG",
              "viewDate": "2012-08-04T19:31:51.698Z"
          },
          /* Some data removed */
      ]
  }

Jedes JSON-Dokument enthält einige Top-Level-Attribute und ein verschachteltes Array von Dokumenten, die Details zu den gestreamten Filmen enthalten.

In der SELECT Klausel können wir mit dem -> Operator auf bestimmte JSON-Attribute verweisen:

 SELECT jsondata->'City' AS City
  FROM customersjson WHERE customerid=1;

    city
------------
  "Sasebo"

Der ->> Operator ist ähnlich, gibt die Daten aber als Text und nicht als JSON formatiert zurück.

Wenn wir innerhalb einer JSONB Spalte suchen wollen, können wir den @> Operator verwenden:

SELECT COUNT(*) FROM customersjson
 WHERE jsondata @> '{"City": "London"}';

  count
---------
      3

Wir können das gleiche Ergebnis mit dem ->> Operator erzielen:

SELECT COUNT(*) FROM customersjson
 WHERE jsondata->>'City' = 'London';

  count
---------
      3

Die Operatoren ->> und @> können unterschiedliche Leistungsmerkmale haben. So kann ->> einen invertierten Index nutzen, während @> einen Tabellenscan verwenden würde.

Wir können die Struktur des JSON-Dokuments mit den Funktionen jsonb_each und jsonb_object_keys abfragen. jsonb_each gibt eine Zeile pro Attribut im JSON-Dokument zurück, während jsonb_object_keys nur die Attributschlüssel zurückgibt. Das ist nützlich, wenn du nicht weißt, was in der Spalte JSONB gespeichert ist.

jsonb_array_elements gibt eine Zeile für jedes Element in einem JSON-Array zurück. Hier erweitern wir zum Beispiel das Array views für einen bestimmten Kunden und zählen die Anzahl der Filme, die er gesehen hat:

SELECT COUNT(jsonb_array_elements(jsondata->'views'))
  FROM customersjson
 WHERE customerid =1;

  count
---------
     37
(1 row)

Zusammenfassung von SELECT

Die Anweisung SELECT ist wahrscheinlich die am häufigsten verwendete Anweisung in der Datenbankprogrammierung und bietet eine große Bandbreite an Funktionen. Selbst nach jahrzehntelanger Arbeit in diesem Bereich kennen wir drei nicht jede Nuance der SELECT Funktionalität. Dennoch haben wir versucht, dir hier die wichtigsten Aspekte der Sprache näher zu bringen. Wenn du mehr wissen willst, schau dir die Dokumentation von CockroachDB an.

Obwohl einige Datenbankexperten fast ausschließlich SELECT verwenden, werden die meisten auch Daten erstellen und bearbeiten. In den folgenden Abschnitten werden wir uns die Sprachfunktionen ansehen, die diese Tätigkeiten unterstützen.

Tabellen und Indizes erstellen

In einer relationalen Datenbank können Daten nur zu vordefinierten Tabellen hinzugefügt werden. Diese Tabellen werden mit der Anweisung CREATE TABLE erstellt. Indizes können erstellt werden, um eindeutige Beschränkungen durchzusetzen oder einen schnellen Zugriff auf die Daten zu ermöglichen. Indizes können innerhalb der Anweisung CREATE TABLE oder durch eine separate Anweisung CREATE INDEX definiert werden.

Die Struktur eines Datenbankschemas ist ein entscheidender Faktor für die Leistung der Datenbank und auch für die Wartbarkeit und den Nutzen der Datenbank. Wir werden die wichtigsten Überlegungen zum Datenbankdesign in Kapitel 5 besprechen. Lass uns zunächst ein paar einfache Tabellen erstellen.

Wir verwenden CREATE TABLE , um eine Tabelle in einer Datenbank zu erstellen. Abbildung 4-5 zeigt eine vereinfachte Syntax für die Anweisung CREATE TABLE .

Create Table Statement
Abbildung 4-5. CREATE TABLE Anweisung

Ein einfaches CREATE TABLE wird im nächsten Beispiel gezeigt. Es erstellt eine Tabelle, mytable, mit einer einzigen Spalte, mycolumn. Die Spalte mycolumn kann nur Integer-Werte speichern:

CREATE TABLE mytable
(
      mycolumn int
);

Die CREATE TABLE Anweisung muss die Spalten definieren, die in der Tabelle vorkommen, und kann optional Indizes, Spaltenfamilien, Beschränkungen und Partitionen für die Tabelle definieren. Die CREATE TABLE Anweisung für die Tabelle rides in der Datenbank movr würde zum Beispiel so aussehen:

CREATE TABLE public.rides (
	id UUID NOT NULL,
	city VARCHAR NOT NULL,
	vehicle_city VARCHAR NULL,
	rider_id UUID NULL,
	vehicle_id UUID NULL,
	start_address VARCHAR NULL,
	end_address VARCHAR NULL,
	start_time TIMESTAMP NULL,
	end_time TIMESTAMP NULL,
	revenue DECIMAL(10,2) NULL,
	CONSTRAINT "primary" PRIMARY KEY (city ASC, id ASC),
	CONSTRAINT fk_city_ref_users
	   FOREIGN KEY (city, rider_id)
	   REFERENCES public.users(city, id),
	CONSTRAINT fk_vehicle_city_ref_vehicles
	   FOREIGN KEY (vehicle_city, vehicle_id)
	   REFERENCES public.vehicles(city, id),
	INDEX rides_auto_index_fk_city_ref_users
	   (city ASC, rider_id ASC),
	INDEX rides_auto_index_fk_vehicle_city_ref_vehicles
          (vehicle_city ASC, vehicle_id ASC),
	CONSTRAINT check_vehicle_city_city
           CHECK (vehicle_city = city)
);

Diese CREATE TABLE Anweisung spezifizierte zusätzliche Spalten, ihre Nullbarkeit, Primär- und Fremdschlüssel, Indizes und Beschränkungen für Tabellenwerte.

Die relevanten Klauseln in Abbildung 4-5 sind in Tabelle 4-2 aufgeführt.

Tabelle 4-2. CREATE TABLE Optionen

column_def

Die Definition einer Spalte. Dazu gehören der Spaltenname, der Datentyp und die Nullbarkeit. Auch spaltenspezifische Einschränkungen können hier angegeben werden, obwohl es besser ist, alle Einschränkungen separat aufzulisten.

index_def

Definition eines Index, der für die Tabelle erstellt werden soll. Wie CREATE INDEX , aber ohne das führende Verb CREATE.

table_constraint

Eine Einschränkung für die Tabelle, z. B. PRIMARY KEY , FOREIGN KEY oder CHECK. Siehe "Einschränkungen" für die Syntax der Einschränkung.

family_def

Weist die Spalten einer Spaltenfamilie zu. In Kapitel 2 findest du weitere Informationen über Spaltenfamilien.

Schauen wir uns nun jede dieser CREATE TABLE Optionen an.

Spaltendefinitionen

Eine Spaltendefinition besteht aus einem Spaltennamen, einem Datentyp, einem Nullbarkeitsstatus, einem Standardwert und möglicherweise aus Constraint-Definitionen auf Spaltenebene. Mindestens der Name und der Datentyp müssen angegeben werden. Abbildung 4-6 zeigt die Syntax für eine Spaltendefinition.

Create Table Statement
Abbildung 4-6. Säulendefinition

Obwohl Beschränkungen direkt mit den Spaltendefinitionen angegeben werden können, können sie auch unabhängig davon unter den Spaltendefinitionen aufgeführt werden. Viele Praktiker ziehen es vor, die Beschränkungen auf diese Weise getrennt aufzulisten, weil so alle Beschränkungen, auch die mehrspaltigen, zusammen gefunden werden können.

Berechnete Spalten

Mit CockroachDB können Tabellen berechnete Spalten enthalten, die in anderen Datenbanken eine View-Definition erfordern würden:

column_name AS expression [STORED|VIRTUAL]

Eine VIRTUAL berechnete Spalte wird immer dann ausgewertet, wenn auf sie verwiesen wird. Ein STORED Ausdruck wird bei seiner Erstellung in der Datenbank gespeichert und muss nicht immerneu berechnet werden.

In dieser Tabellendefinition sind zum Beispiel die Spalten firstName und lastName zu einer Spalte fullName verkettet:

CREATE TABLE people
 (
     id INT PRIMARY KEY,
     firstName VARCHAR NOT NULL,
     lastName VARCHAR NOT NULL,
     dateOfBirth DATE NOT NULL,
     fullName STRING AS (CONCAT(firstName,' ',lastName) ) STORED

 );

Die berechneten Spalten dürfen nicht kontextabhängig sein. Das heißt, der berechnete Wert darf sich nicht im Laufe der Zeit ändern oder anderweitig nicht deterministisch sein. Die berechnete Spalte im folgenden Beispiel würde zum Beispiel nicht funktionieren, da die Spalte age statisch wäre und nicht jedes Mal neu berechnet würde. Auch wenn es schön wäre, das Altern im echten Leben zu stoppen, wollen wir wahrscheinlich, dass die Spalte age im Laufe der Zeit wächst.

CREATE TABLE people
 (
     id INT PRIMARY KEY,
     firstName VARCHAR NOT NULL,
     lastName VARCHAR NOT NULL,
     dateOfBirth timestamp NOT NULL,
     fullName STRING AS (CONCAT(firstName,' ',lastName) ) STORED,
     age int AS (now()-dateOfBirth) STORED
 );

Datenarten

Die Basis-Datentypen der CockroachDB sind in Tabelle 4-3 aufgeführt.

Tabelle 4-3. CockroachDB Datentypen
Type Beschreibung Beispiel

ARRAY

Ein 1-dimensionales, 1-indiziertes, homogenes Array eines beliebigen Nicht-Array-Datentyps.

{"Himmel", "Straße", "Auto"}

BIT

Eine Kette von binären Ziffern (Bits).

B'10010101'

BOOL

Ein boolescher Wert.

wahr

BYTES

Eine Zeichenkette aus binären Zeichen.

b’\141\061\142\062\143\063’

COLLATE

Mit der Funktion COLLATE kannst du die Werte von STRING nach sprach- und länderspezifischen Regeln, den so genannten Kollationen, sortieren.

a1b2c3 COLLATE de

DATE

Eine Verabredung.

DATUM 2016-01-25

ENUM

Neu in v20.2: Ein benutzerdefinierter Datentyp, der aus einer Reihe von statischen Werten besteht.

ENUM(Kreuz, Karo, Herz, Pik)

DECIMAL

Eine exakte Festkommazahl.

1.2345

FLOAT

Eine 64-Bit, ungenaue Fließkommazahl.

3.141592653589793

INET

Eine IPv4- oder IPv6-Adresse.

192.168.0.1

INT

Eine ganze Zahl mit Vorzeichen, bis zu 64 Bit.

12345

INTERVAL

Eine Zeitspanne.

INTERVALL 2h30m30s

JSONB

JSON-Daten.

{"first_name": "Lola", "last_name": "Hund", "Ort": "NYC", "online" : true, "Freunde" : 547}

SERIAL

Ein Pseudotyp, der eindeutige aufsteigende Zahlen erzeugt.

148591304110702593

STRING

Eine Kette von Unicode-Zeichen.

a1b2c3

TIME TIMETZ

TIME speichert eine Tageszeit in UTC. TIMETZ konvertiert TIME Werte mit einem bestimmten Zeitzonen-Offset von UTC.

TIME 01:23:45.123456 TIMETZ 01:23:45.123456-5:00

TIMESTAMP TIMESTAMPTZ

TIMESTAMP speichert eine Datums- und Zeitkombination in UTC.TIMESTAMPTZ konvertiert TIMESTAMP Werte mit einem bestimmten Zeitzonen-Offset von UTC.

TIMESTAMP 2016-01-25 10:10:10TIMESTAMPTZ 2016-01-25 10:10:10-05:00

UUID

Ein 128-Bit-Hexadezimalwert.

7f9c24e8-3b12-4fef-91e0-56a2d5a246ec

Beachte, dass diese CockroachDB-Basistypen auch für andere Datentypen verwendet werden können. Zum Beispiel sind die PostgreSQL-Typen BIGINT und SMALLINT mit dem CockroachDB-Typ INT verknüpft.

In CockroachDB können Datentypen gecastet - oder konvertiert - werden, indem der Datentyp mit "::" an einen Ausdruck angehängt wird. Zum Beispiel:

SELECT revenue::int FROM rides;

Die Funktion CAST kann auch verwendet werden, um Datentypen zu konvertieren und ist mit anderen Datenbanken und SQL-Standards weitgehend kompatibel. Zum Beispiel:

SELECT CAST(revenue AS int) FROM rides;

Primärschlüssel

Wie wir wissen, definiert ein Primärschlüssel eindeutig eine Zeile innerhalb einer Tabelle. In CockroachDB ist ein Primärschlüssel obligatorisch, da alle Tabellen auf der Grundlage der Bereiche ihres Primärschlüssels über den Cluster verteilt werden. Wenn du keinen Primärschlüssel angibst, wird automatisch ein Schlüssel für dich erzeugt.

In anderen Datenbanken ist es üblich, einen automatisch generierten Primärschlüssel mit Klauseln wie AUTOINCREMENT zu definieren. Die Generierung von Primärschlüsseln in verteilten Datenbanken ist ein wichtiges Thema, denn der Primärschlüssel wird verwendet, um die Daten auf die Knoten im Cluster zu verteilen. Wir werden die Optionen für die Erzeugung von Primärschlüsseln im nächsten Kapitel besprechen, aber für den Moment reicht es aus, wenn du feststellst, dass du zufällige Primärschlüsselwerte mit dem Datentyp UUID und der Funktion gen_random_uuid() als Standardwert erzeugen kannst:

CREATE TABLE people (
        id UUID NOT NULL DEFAULT gen_random_uuid(),
        firstName VARCHAR NOT NULL,
        lastName VARCHAR NOT NULL,
        dateOfBirth DATE NOT NULL
 );

Diese Methode gilt als bewährte Methode, um eine gleichmäßige Verteilung der Schlüssel im Cluster zu gewährleisten. Andere Optionen für die automatische Generierung von Primärschlüsseln werden in Kapitel 5 besprochen.

Zwänge

Die CONSTRAINT Klausel legt Bedingungen fest, die von allen Zeilen in einer Tabelle erfüllt werden müssen. Unter bestimmten Umständen kann das Schlüsselwort CONSTRAINT weggelassen werden, z.B. wenn eine Spaltenbeschränkung oder bestimmte Beschränkungstypen wie PRIMARY KEY oder FOREIGN KEY definiert werden. Abbildung 4-7 zeigt die allgemeine Form einer Constraint-Definition.

Constraint Statement
Abbildung 4-7. CONSTRAINT Anweisung

Eine UNIQUE -Beschränkung erfordert, dass alle -Werte für column oder column_list eindeutig sind.

PRIMARY KEY implementiert einen Satz von Spalten, die eindeutig sein müssen und die auch Gegenstand einer FOREIGN KEY Einschränkung in einer anderen Tabelle sein können. Sowohl die PRIMARY KEY als auch die UNIQUE Constraints erfordern die Erstellung eines impliziten Indexes. Falls gewünscht, können die Eigenschaften der physischen Speicherung des Indexes in der USING Klausel angegeben werden. Die Optionen der USING INDEX Klausel haben die gleiche Bedeutung wie in der CREATE INDEX Anweisung.

NOT NULL zeigt an, dass die betreffende Spalte nicht NULL sein darf. Diese Option steht nur für Spaltenbeschränkungen zur Verfügung, aber der gleiche Effekt kann mit einer Tabellenbeschränkung CHECK erzielt werden.

CHECK definiert einen Ausdruck, der für jede Zeile der Tabelle den Wert true haben muss. Die bewährten Methoden zur Erstellung von Constraints werden in Kapitel 5 besprochen.

Der sinnvolle Einsatz von Constraints kann dazu beitragen, die Datenqualität sicherzustellen und der Datenbank ein gewisses Maß an Selbstdokumentation zu geben. Einige Constraints haben jedoch erhebliche Auswirkungen auf die Leistung; wir werden diese Auswirkungen in Kapitel 5 erörtern.

Indizes

Indizes können durch die CREATE INDEX Anweisung erstellt werden oder eine INDEX Definition kann in die CREATE TABLE Anweisung aufgenommen werden.

Wir haben in Kapitel 2 viel über Indizes gesprochen und werden in den Kapiteln über Schemadesign und Performance-Tuning (Kapitel 5 bzw. 8) weiter über Indizes sprechen. Eine effektive Indexierung ist einer der wichtigsten Erfolgsfaktoren für eine leistungsfähige CockroachDB-Implementierung.

Abbildung 4-8 zeigt eine vereinfachte Syntax für dieAnweisung CockroachDB CREATE INDEX .

Create Index Statement
Abbildung 4-8. CREATE INDEX Anweisung

In Kapitel 2 haben wir uns mit den Interna der CockroachDB-Indizes beschäftigt. Aus Sicht der Leistung verhalten sich CockroachDB-Indizes ähnlich wie Indizes in anderen Datenbanken - sie bieten eine schnelle Zugriffsmethode zum Auffinden von Zeilen mit einem bestimmten Satz von nicht primären Schlüsselwerten. Wenn wir zum Beispiel einfach eine Zeile mit einem bestimmten Namen und Geburtsdatum finden wollen, könnten wir den folgenden mehrspaltigen Index erstellen:

CREATE INDEX people_namedob_ix ON people
 (lastName,firstName,dateOfBirth);

Wenn wir zusätzlich sicherstellen wollen, dass keine zwei Zeilen den gleichen Wert für Name und Geburtsdatum haben, können wir einen eindeutigen Index erstellen:

CREATE UNIQUE INDEX people_namedob_ix ON people
 (lastName,firstName,dateOfBirth);

Die STORING Klausel erlaubt es uns, zusätzliche Daten im Index zu speichern, die es uns ermöglichen, Abfragen allein mit dem Index zu erfüllen. Dieser Index kann zum Beispiel Abfragen erfüllen, die Telefonnummern für einen bestimmten Namen und ein bestimmtes Geburtsdatum abfragen:

CREATE UNIQUE INDEX people_namedob_ix ON people
 (lastName,firstName,dateOfBirth) STORING (phoneNumber);

Invertierte Indizes

Ein invertierter Index kann verwendet werden, um die Elemente in einem Array oder die Attribute in einem JSON-Dokument zu indizieren. In Kapitel 2 haben wir uns die Interna von invertierten Indizes angesehen. Invertierte Indizes können auch für räumliche Daten verwendet werden.

Nehmen wir zum Beispiel an, unsere Tabelle people verwendet ein JSON-Dokument, um die Attribute einer Person zu speichern:

CREATE TABLE people
 ( id UUID NOT NULL DEFAULT gen_random_uuid(),
   personData JSONB );

INSERT INTO people (personData)
VALUES('{
	  "firstName":"Guy",
        "lastName":"Harrison",
        "dob":"21-Jun-1960",
        "phone":"0419533988",
        "photo":"eyJhbGciOiJIUzI1NiIsI..."
     }');

Wir könnten einen invertierten Index wie folgt erstellen:

CREATE INVERTED INDEX people_inv_idx ON
people(personData);

Das würde Abfragen des JSON-Dokuments wie die folgende unterstützen:

SELECT *
FROM people
WHERE personData @> '{"phone":"0419533988"}';

Bedenke, dass invertierte Indizes jedes Attribut im JSON-Dokument indizieren, nicht nur die, nach denen du suchen willst. Das kann zu einem sehr großen Index führen. Daher ist es vielleicht sinnvoller, eine berechnete Spalte für das JSON-Attribut zu erstellen und dann einen Index für diese berechnete Spalte zu erstellen:

ALTER TABLE people ADD phone STRING AS (personData->>'phone') VIRTUAL;

CREATE INDEX people_phone_idx ON people(phone);

Hash-sharded-Indizes

Wenn du mit einer Tabelle arbeitest, die auf sequenziellen Schlüsseln indiziert werden muss, solltest du Hash-Sharded-Indizes verwenden. Hash-Sharded-Indizes verteilen den sequentiellen Datenverkehr gleichmäßig über die Bereiche. Dadurch werden Hotspots in einzelnen Bereichen vermieden und die Schreibleistung von Indizes mit sequentiellen Schlüsseln verbessert, ohne die Leseleistung zu beeinträchtigen:

CREATE TABLE people
( id INT PRIMARY KEY,
  firstName VARCHAR NOT NULL,
  lastName VARCHAR NOT NULL,
  dateOfBirth timestamp NOT NULL,
  phoneNumber VARCHAR NOT NULL,
  serialNo SERIAL ,
  INDEX serialNo_idx (serialNo) USING HASH WITH BUCKET_COUNT=4);

Wir werden Hash-Sharded-Indizes und andere fortgeschrittene Indizierungsthemen im nächsten Abschnitt genauer besprechen.

TABELLE ERSTELLEN AS SELECT

Die AS SELECT Klausel von CREATE TABLE ermöglicht es uns, eine neue Tabelle zu erstellen, die die Daten und Attribute einer SQL SELECT Anweisung enthält. Spalten, Beschränkungen und Indizes können für eine bestehende Tabelle angegeben werden, müssen aber mit den Datentypen und der Anzahl der Spalten übereinstimmen, die von der SELECT Anweisung zurückgegeben werden. In diesem Beispiel erstellen wir eine Tabelle, die auf einer JOIN und einer Aggregation von zwei Tabellen in der Datenbank movr basiert:

CREATE TABLE user_ride_counts AS
SELECT u.name, COUNT(u.name) AS rides
  FROM "users" AS u JOIN "rides" AS r
    ON (u.id=r.rider_id)
 GROUP BY u.name;

Beachte, dass CREATE TABLE AS SELECT zwar zum Erstellen von Übersichtstabellen und ähnlichem verwendet werden kann, CREATE MATERIALIZED VIEW aber eine funktionalere Alternative darstellt.

Tische ändern

Die Anweisung ALTER TABLE ermöglicht es, Spalten der Tabelle oder Constraints hinzuzufügen, zu ändern, umzubenennen oder zu entfernen sowie Constraints zu überprüfen und zu partitionieren. Abbildung 4-9 zeigt die Syntax.

Die Online-Änderung von Tabellenstrukturen sollte nicht auf die leichte Schulter genommen werden, obwohl CockroachDB sehr fortschrittliche Mechanismen bietet, um solche Änderungen ohne Beeinträchtigung der Verfügbarkeit und mit minimalen Auswirkungen auf die Leistung weiterzugeben. Wir werden die Verfahren für Online-Schemaänderungen in späteren Kapiteln besprechen.

Alter Table Statement
Abbildung 4-9. ALTER TABLE Anweisung

Tische fallen lassen

Tabellen können mit der Anweisung DROP TABLE gelöscht werden. Abbildung 4-10 zeigt die Syntax.

Drop Table Statement
Abbildung 4-10. DROP TABLE Anweisung

Mehrere Tabellen können mit einer einzigen DROP TABLE Anweisung entfernt werden. Das Schlüsselwort CASCADE bewirkt, dass auch abhängige Objekte wie Views oder Fremdschlüsselbegrenzungen gelöscht werden. RESTRICT-der Standardwert- hat den gegenteiligen Effekt: Wenn es abhängige Objekte gibt, wird die Tabelle nicht gelöscht.

Ansichten

Eine Standardansicht ist eine Abfragedefinition die in der Datenbank gespeichert ist und eine virtuelle Tabelle definiert. Auf diese virtuelle Tabelle kann auf die gleiche Weise wie auf eine reguläre Tabelle verwiesen werden. Common Table Expressions können als eine Art temporärer View für eine einzelne SQL-Anweisung betrachtet werden. Wenn du einen Common Table Expression hast, den du in verschiedenen SQL-Anweisungen verwenden möchtest, wäre ein View eine logische Lösung.

Eine materialisierte Ansicht speichert die Ergebnisse der Ansichtsdefinition in der Datenbank, so dass die Ansicht nicht jedes Mal neu ausgeführt werden muss, wenn sie aufgerufen wird. Das verbessert die Leistung, kann aber zu veralteten Ergebnissen führen. Wenn du dir eine Ansicht als eine gespeicherte Abfrage vorstellst, kann eine materialisierte Ansicht als ein gespeichertes Ergebnis betrachtet werden.

Abbildung 4-11 zeigt die Syntax der Anweisung CREATE VIEW.

Create View Statement
Abbildung 4-11. CREATE VIEW Anweisung

Die Anweisung REFRESH MATERIALIZED VIEW kann verwendet werden, um die Daten zu aktualisieren, die einer materialisierten Ansicht zugrunde liegen.

Daten einfügen

Wir können Daten in eine neue Tabelle laden, indem wir die bereits erwähnte CREATE TABLE AS SELECT Anweisung verwenden, die INSERT Anweisung innerhalb eines Programms oder von der Kommandozeile aus verwenden oder externe Daten mit der IMPORT Anweisung laden. Es gibt auch Dienstprogramme, die keine SQL-Anweisungen sind, um Daten einzufügen - wir werden uns diese in Kapitel 7 ansehen.

Die altehrwürdige Anweisung INSERT fügt Daten zu einer bestehenden Tabelle hinzu. Abbildung 4-12 zeigt eine vereinfachte Syntax für die Anweisung INSERT.

Insert Statement
Abbildung 4-12. INSERT Anweisung

INSERT nimmt entweder eine Reihe von Werten oder eine SELECT Anweisung an. Im folgenden Beispiel fügen wir zum Beispiel eine einzelne Zeile in die Tabelle people ein:

INSERT INTO people (firstName, lastName, dateOfBirth)
VALUES('Guy', 'Harrison', '21-JUN-1960');

Die VALUES Klausel der INSERT Anweisung kann Array-Werte akzeptieren, so dass mehr als eine Zeile in einer einzigen Ausführung eingefügt werden kann:

INSERT INTO people (firstName, lastName, dateOfBirth)
VALUES ('Guy', 'Harrison', '21-JUN-1960'),
       ('Michael', 'Harrison', '19-APR-1994'),
        ('Oriana', 'Harrison', '18-JUN-2020');

Es gibt alternative Möglichkeiten, Stapel in die verschiedenen Programmsprachtreiber einzufügen, und wir werden in Kapitel 7 einige Beispiele zeigen.

Als Quelle für die eingefügten Daten kann eine SELECT Anweisung angegeben werden:

INSERT INTO people (firstName, lastName, dateOfBirth)
SELECT firstName, lastName, dateOfBirth
  FROM peopleStagingData;

Mit der RETURNING Klausel können die eingefügten Daten an den Benutzer zurückgegeben werden. Zu den zurückgegebenen Daten gehören nicht nur die eingefügten Variablen, sondern auch alle automatisch generierten Daten. In diesem Fall haben wir zum Beispiel INSERT Daten ohne Angabe eines ID-Werts eingefügt und bekommen die ID-Werte, die erstellt wurden, zurückgegeben:

INSERT INTO people (firstName, lastName, dateOfBirth)
VALUES ('Guy', 'Harrison', '21-JUN-1960'),
       ('Michael', 'Harrison', '19-APR-1994'),
        ('Oriana', 'Harrison', '18-JUN-2020')
  RETURNING id;

Mit der ON CONFLICT Klausel kannst du steuern, was passiert, wenn eine INSERT eine Eindeutigkeitsbeschränkung verletzt. Abbildung 4-13 zeigt die Syntax.

On Conflict Clause
Abbildung 4-13. ON CONFLICT Klausel

Ohne die ON CONFLICT Klausel führt eine Verletzung der Einzigartigkeitsbeschränkung zum Abbruch der gesamten INSERT Anweisung. DO NOTHING lässt die INSERT Anweisung als Ganzes erfolgreich sein, ignoriert aber alle Einfügungen, die gegen die Einzigartigkeitsklausel verstoßen. Mit der DO UPDATE Klausel kannst du eine UPDATE Anweisung angeben, die anstelle der INSERT Anweisung ausgeführt wird. Die DO UPDATE Funktion ähnelt in ihrer Funktionsweise der UPSERT Anweisung, die weiter unten in diesem Kapitel besprochen wird.

UPDATE

Die Anweisung UPDATE ändert bestehende Daten in einer Tabelle.Abbildung 4-14 zeigt eine vereinfachte Syntax für die Anweisung UPDATE.

Update Statement
Abbildung 4-14. UPDATE Anweisung

Eine UPDATE Anweisung kann statische Werte angeben, wie im folgenden Beispiel:

UPDATE users
  SET address = '201 E Randolph St',
  	  city='amsterdam'
 WHERE name='Maria Weber';

Alternativ können die Werte auch ein Ausdruck sein, der auf bestehende Werte verweist:

UPDATE user_promo_codes
   SET usage_count=usage_count+1
  WHERE user_id='297fcb80-b67a-4c8b-bf9f-72c404f97fe8';

Oder die UPDATE kann eine Unterabfrage verwenden, um die Werte zu erhalten:

 UPDATE rides SET (revenue, start_address) =
    (SELECT revenue, end_address FROM rides
      WHERE id = '94fdf3b6-45a1-4800-8000-000000000123')
 WHERE id = '851eb851-eb85-4000-8000-000000000104';

Die RETURNING Klausel kann verwendet werden, um die geänderten Spalten anzuzeigen. Dies ist besonders nützlich, wenn eine Spalte durch eine Funktion aktualisiert wird und wir den geänderten Wert an die Anwendung zurückgeben wollen:

UPDATE user_promo_codes
   SET usage_count=usage_count+1
  WHERE user_id='297fcb80-b67a-4c8b-bf9f-72c404f97fe8'
 RETURNING (usage_count);

UPSERT

UPSERT kann in einem einzigen Vorgang neue Daten einfügen und bestehende Daten in einer Tabelle aktualisieren. Wenn die Eingabedaten keine Eindeutigkeitsbeschränkungen verletzen, werden sie eingefügt. Wenn eine Eingabe mit einem vorhandenen Primärschlüssel übereinstimmt, werden die Werte der betreffenden Zeile aktualisiert.

In CockroachDB bietet die ON CONFLICT Klausel von INSERT einen ähnlichen - wenn auch flexibleren - Mechanismus. Wenn diese Flexibilität nicht benötigt wird, ist UPSERT wahrscheinlich schneller als eine ähnliche INSERT...ON CONFLICT DO UPDATE Anweisung.

Abbildung 4-15 zeigt die Syntax der Anweisung UPSERT.

Upsert Statement
Abbildung 4-15. UPSERT Anweisung

Die UPSERT vergleicht den Primärschlüsselwert jeder angegebenen Zeile. Wenn der Primärschlüssel in der vorhandenen Tabelle nicht gefunden wird, wird eine neue Zeile erstellt. Andernfalls wird die vorhandene Zeile mit den neuen Werten aktualisiert.

Die RETURNING Klausel kann verwendet werden, um eine Liste der aktualisierten oder eingefügten Zeilen zurückzugeben.

In diesem Beispiel ist der Primärschlüssel von user_promo_codes (city, user_id, code) . Wenn ein Benutzer bereits einen Eintrag für diese Kombination in der Tabelle hat, wird diese Zeile mit einem user_count von 0 aktualisiert. Ansonsten wird eine neue Zeile mit diesen Werten erstellt.

UPSERT INTO user_promo_codes
  (user_id,city,code,timestamp,usage_count)
SELECT id,city,'NewPromo',now(),0
  FROM "users";

LÖSCHEN

DELETE können Daten aus einer Tabelle entfernt werden. Abbildung 4-16 zeigt eine vereinfachte Syntax für die Anweisung DELETE.

Delete Statement
Abbildung 4-16. DELETE Anweisung

Meistens akzeptiert eine DELETE Anweisung eine WHERE Klausel und nicht viel mehr. Hier löschen wir zum Beispiel eine einzelne Zeile in der Tabelle people:

DELETE FROM people
 WHERE firstName='Guy'
   AND lastName='Harrison';

Die RETURNING Klausel kann Details zu den entfernten Zeilen zurückgeben. Zum Beispiel:

DELETE FROM user_promo_codes
 WHERE code='NewPromo'
RETURNING(user_id);

Du kannst auch eine ORDER BY und LIMIT Klausel einfügen, um Batch-Löschungen auf inkrementelle Weise durchzuführen. Du kannst zum Beispiel eine DELETE Anweisung erstellen, um die ältesten 1.000 Zeilen zu löschen. Weitere Informationen findest du in der CockroachDB-Dokumentation.

TRUNCATE

TRUNCATE bietet einen schnellen Mechanismus zum Entfernen aller Zeilen aus einer Tabelle. Intern ist er als DROP TABLE gefolgt von einem CREATE TABLE implementiert. TRUNCATE ist nicht transaktional - du kannst nicht ROLLBACK TRUNCATE .

IMPORTIEREN/IMPORTIEREN IN

Die Anweisung IMPORT importiert die folgenden Datentypen in CockroachDB:

  • Avro

  • Kommagetrennte Werte (CSV)/Tabellengetrennte Werte (TSV)

  • Postgres Dump-Dateien

  • MySQL-Dump-Dateien

  • CockroachDB Dump-Dateien

IMPORT erstellt eine neue Tabelle, während IMPORT INTO einen Import in eine bestehende Tabelle ermöglicht.

Die zu importierenden Dateien sollten entweder in einem Bucket der Cloud Speicherung - Google Cloud Storage, Amazon S3 oder Azure Blob Storage - über eine HTTP-Adresse oder im lokalen Dateisystem ("nodelocal") vorhanden sein.

Die verschiedenen Möglichkeiten, Daten in CockroachDB zu laden, werden wir in Kapitel 7 besprechen. Für den Moment wollen wir jedoch eine neue Tabelle customers aus einer CSV-Datei erstellen:

 IMPORT INTO TABLE customers (
        id INT PRIMARY KEY,
        name STRING,
        INDEX name_idx (name)
);
CSV DATA ('nodelocal://1/customers.csv');
        job_id       |  status   | fra | rows | index_entries | bytes
---------------------+-----------+-----+------+---------------+--------
  659162639684534273 | succeeded |   1 |    1 |             1 |    47
(1 row)

Time: 934ms total (execution 933ms / network 1ms)

Bei einem Ein-Knoten-Demo-Cluster hängt der Speicherort nodelocal ein wenig von deiner Installation ab, befindet sich aber häufig in einem extern Verzeichnis unterhalb des CockroachDB-Installationsverzeichnisses.

Transaktionsanweisungen

Wir haben in Kapitel 2 viel über CockroachDB-Transaktionen gesprochen. Wenn du also noch einmal wissen willst, wie CockroachDB-Transaktionen funktionieren, solltest du dieses Kapitel lesen. Aus Sicht der SQL-Sprache unterstützt CockroachDB die Standard-SQL-Anweisungen zur Transaktionssteuerung.

BEGIN-Transaktion

Die Anweisung BEGIN leitet eine Transaktion ein und legt deren Eigenschaften fest. Abbildung 4-17 zeigt die Syntax.

PRIORITY legt die Priorität der Transaktion fest. Im Falle eines Konflikts ist es weniger wahrscheinlich, dass Transaktionen mit der Priorität HIGH erneut versucht werden.

READ ONLY legt fest, dass die Transaktion schreibgeschützt ist und die Daten nicht verändert werden.

BeginTransaction
Abbildung 4-17. BEGIN Transaktion

AS OF SYSTEM TIME ermöglicht es einer READ ONLY Transaktion, Daten aus einem Snapshot der Datenbankhistorie einzusehen. Darauf werden wir auf den nächsten Seiten zurückkommen.

SAVEPOINT

SAVEPOINT erstellt einen benannten Rollback-Punkt , der als Ziel einer Anweisung ROLLBACK verwendet werden kann. Dadurch kann ein Teil einer Transaktion verworfen werden, ohne dass die gesamte Arbeit der Transaktion verworfen wird. Weitere Einzelheiten findest du im Abschnitt ROLLBACK.

COMMIT

Die Anweisung COMMIT überträgt die aktuellen Transaktionen und macht die Änderungen dauerhaft.

Beachte, dass bei einigen Transaktionen ein client-seitiger Eingriff erforderlich sein kann, um Wiederholungen zu ermöglichen. Diese Muster werden in Kapitel 6 näher erläutert.

ROLLBACK

ROLLBACK bricht die aktuelle Transaktion ab. Optional können wir ROLLBACK zu einem Savepoint zurückkehren, der nur die Anweisungen zurücknimmt, die nach dem SAVEPOINT ausgegeben wurden.

Im folgenden Beispiel wird die Einfügung des falsch geschriebenen Zahlenbaums zurückgenommen und korrigiert, ohne dass die Transaktion als Ganzes abgebrochen wird:

BEGIN ;

INSERT INTO numbers VALUES(1,'one');
INSERT INTO numbers VALUES(2,'two');
SAVEPOINT two;

INSERT INTO numbers VALUES(3,'tree');
ROLLBACK TO SAVEPOINT two;

INSERT INTO numbers VALUES(3,'three');
COMMIT;

ZUM UPDATE AUSWÄHLEN

Die FOR UPDATE Klausel einer SELECT Anweisung sperrt die von einer Abfrage zurückgegebenen Zeilen und stellt sicher, dass sie zwischen dem Zeitpunkt des Lesens und dem Ende der Transaktion nicht von einer anderen Transaktion geändert werden können. Diese Klausel wird normalerweise verwendet, um das pessimistische Sperrmuster zu implementieren, das wir in Kapitel 6 besprechen werden.

Eine FOR UPDATE Abfrage sollte innerhalb einer Transaktion ausgeführt werden. Andernfalls werden die Sperren nach Beendigung der SELECT Anweisung freigegeben.

Eine FOR UPDATE innerhalb einer Transaktion blockiert standardmäßig andere FOR UPDATE Anweisungen für dieselben Zeilen oder andere Transaktionen, die diese Zeilen aktualisieren wollen, bis eine COMMIT oder ROLLBACK ausgegeben wird. Wenn jedoch eine Transaktion mit höherer Priorität versucht, die Zeilen zu aktualisieren oder eine FOR UPDATE auszustellen, wird die Transaktion mit niedrigerer Priorität abgebrochen und muss erneut versucht werden.

Wir werden die Mechanismen der Transaktionswiederholungen in Kapitel 6 besprechen.

Abbildung 4-18 veranschaulicht zwei FOR UPDATE Anweisungen, die gleichzeitig ausgeführt werden. Die erste FOR UPDATE hält Sperren für die betroffenen Zeilen und verhindert, dass die zweite Sitzung diese Sperren erhält, bis die erste Sitzung ihre Transaktion abgeschlossen hat.

forUpdateFlow
Abbildung 4-18. FOR UPDATE Klauselverhalten

AB DER SYSTEMZEIT

Die AS OF SYSTEM TIME Klausel kann auf SELECT und BEGIN TRANSACTION Anweisungen sowie in BACKUP und RESTORE Operationen angewendet werden. AS OF SYSTEM TIME gibt an, dass eine SELECT Anweisung oder alle Anweisungen in einer READ ONLY Transaktion auf einem Snapshot der Datenbank zu diesem Systemzeitpunkt ausgeführt werden sollen. Diese Snapshots werden durch die in Kapitel 2 beschriebene MVCC-Architektur zur Verfügung gestellt.

Die Zeit kann als Offset oder als absoluter Zeitstempel angegeben werden, wie in den folgenden zwei Beispielen:

SELECT * FROM rides r
   AS OF SYSTEM TIME '-1d';

 SELECT * FROM rides r
   AS OF SYSTEM TIME '2021-5-22 18:02:52.0+00:00';

Die angegebene Zeit darf in Sekunden nicht älter sein als der Konfigurationsparameter der Replikationszone ttlseconds, der das maximale Alter der MVCC-Snapshots bestimmt.

Es ist auch möglich, mit dem Argument with_max_staleness begrenzte stale reads anzugeben:

SELECT * FROM rides r
    AS OF SYSTEM TIME with_max_staleness('10s')
 WHERE city='amsterdam'
   AND id='aaaae297-396d-4800-8000-0000000208d6';

Mit Bounded Stale Reads kann die Leistung in verteilten Implementierungen optimiert werden, indem CockroachDB die Leseanforderungen von lokalen Replikaten erfüllt, die möglicherweise leicht veraltete Daten enthalten. Wir werden in Kapitel 11 auf Bounded Stale Reads zurückkommen.

Andere Ziele der Datendefinitionssprache

Bisher haben wir uns mit SQL beschäftigt, um Daten in Tabellen und Indizes zu erstellen, zu ändern und zu manipulieren. Diese Objekte stellen in CockroachDB, wie auch in anderen SQL-Datenbanken, den Kern der Datenbankfunktionalität dar. Die CockroachDB Data Definition Language (DDL) bietet jedoch Unterstützung für eine Vielzahl anderer, weniger häufig verwendeter Objekte. Eine vollständige Referenz für alle diese Objekte würde mehr Platz beanspruchen, als wir hier zur Verfügung haben - eine vollständige Liste der CockroachDB-SQL-Objekte findest du in der CockroachDB-Dokumentation.

In Tabelle 4-4 sind einige der anderen Objekte aufgeführt, die in den Anweisungen CREATE, ALTER und DROP manipuliert werden können.

Tabelle 4-4. Andere Objekte des CockroachDB-Schemas
Object Beschreibung

Database

Eine Datenbank ist ein Namensraum innerhalb eines CockroachDB-Clusters, der Schemas, Tabellen, Indizes und andere Objekte enthält. Datenbanken werden in der Regel verwendet, um Objekte zu trennen, die unterschiedliche Anwendungszuständigkeiten oder Sicherheitsrichtlinien haben.

Schema

Ein Schema ist eine Sammlung von Tabellen und Indizes, die zu demselben relationalen Modell gehören. In den meisten Datenbanken werden die Tabellen standardmäßig im Schema PUBLIC erstellt.

Sequence

Oft werden Sequenzen verwendet, um Primärschlüsselwerte zu erzeugen; in CockroachDB gibt es jedoch oft bessere Alternativen. In Kapitel 5 findest du weitere Hinweise zur Erzeugung von Primärschlüsseln.

Role

Eine Rolle wird verwendet, um Datenbank- und Schemarechte zu gruppieren, die dann den Benutzern als Einheit gewährt werden können. In Kapitel 12 findest du weitere Informationen zu den Sicherheitspraktiken von CockroachDB.

Type

In CockroachDB ist ein Typ eine Aufzählung von Werten, die in einer CREATE oder ALTER TABLE Anweisung auf eine Spalte angewendet werden können.

User

Ein Benutzer ist ein Konto, mit dem man sich bei der Datenbank anmelden kann und dem man bestimmte Rechte zuweisen kann. In Kapitel 12 findest du weitere Details zu den Sicherheitspraktiken der CockroachDB.

Statistics

Statistiken bestehen aus Informationen über die Daten in einer bestimmten Tabelle, die der SQL-Optimierer verwendet, um den bestmöglichen Ausführungsplan für eine SQL-Anweisung zu ermitteln. In Kapitel 8 findest du weitere Informationen zur Abfrageoptimierung.

changefeed

Ein Changefeed überträgt Änderungen auf Zeilenebene für nominierte Tabellen an ein Client-Programm. In Kapitel 7 findest du weitere Informationen zur Implementierung von Changefeeds.

Schedule

Ein Zeitplan steuert die regelmäßige Ausführung von Backups. In Kapitel 11 findest du Hinweise zu Backup-Richtlinien.

Administrative Befehle

CockroachDB unterstützt Befehle zur Authentifizierung von Benutzern und deren Berechtigung, Datenbankoperationen durchzuführen. Außerdem verfügt es über ein Zeitplannungsprogramm, mit dem Sicherungs- und Wiederherstellungsvorgänge sowie geplante Schemaänderungen geplant werden können. Andere Befehle unterstützen die Verwaltung der Clustertopologie.

Diese Befehle sind in der Regel eng mit bestimmten Verwaltungsvorgängen verknüpft, die wir in den folgenden Kapiteln besprechen werden, weshalb wir sie hier nicht im Detail definieren. Du kannst die Definitionen für diese Befehle jederzeit in der CockroachDB-Dokumentation nachlesen. Tabelle 4-5 fasst die wichtigsten dieser Befehle zusammen.

Tabelle 4-5. CockroachDB administrative Befehle
Befehl Beschreibung

CANCEL JOB

Abbrechen von Aufträgen, die lange laufen, wie z.B. Backups, Schemaänderungen oder Statistiksammlungen.

CANCEL QUERY

Abbrechen einer laufenden Abfrage.

CANCEL SESSION

Abbrechen und Trennen einer aktuell verbundenen Sitzung.

CONFIGURE ZONE

CONFIGURE ZONE kann verwendet werden, um Replikationszonen für Tabellen, Datenbanken, Bereiche oder Partitionen zu ändern. In Kapitel 10 findest du weitere Informationen zur Zonenkonfiguration.

SET CLUSTER SETTING

Ändere einen Parameter der Clusterkonfiguration.

EXPLAIN

Zeigt einen Ausführungsplan für eine SQL-Anweisung an. Wir werden uns EXPLAIN in Kapitel 8 genauer ansehen.

EXPORT

Dump der SQL-Ausgabe in CSV-Dateien.

SHOW/CANCEL/PAUSE JOBS

Verwalte Hintergrundaufträge - Importe, Backups, Schemaänderungen usw. - in der Datenbank.

SET LOCALITY

Ändere die Lokalität einer Tabelle in einer multiregionalen Datenbank. Siehe Kapitel 10 für weitere Informationen.

SET TRACING

Aktiviere das Tracing für eine Sitzung. Wir werden dies in Kapitel 8 besprechen.

SHOW RANGES

Zeigt, wie eine Tabelle, ein Index oder eine Datenbank in Bereiche unterteilt wird. In Kapitel 2 wird erläutert, wie CockroachDB Daten in Bereiche aufteilt.

SPLIT AT

Erzwinge einen Bereichssplit an der angegebenen Zeile in einer Tabelle oder einem Index.

BACKUP

Erstelle eine konsistente Sicherung für eine Tabelle oder Datenbank. In Kapitel 11 findest du Hinweise zu Backups und Hochverfügbarkeit.

SHOW STATISTICS

Optimierungsstatistiken für eine Tabelle anzeigen.

SHOW TRACE FOR SESSION

Zeigt Tracing-Informationen für eine Sitzung an, die mit dem Befehl SET TRACING erstellt wurde.

SHOW TRANSACTIONS

Aktuell laufende Transaktionen anzeigen

SHOW SESSION

Zeigt Sitzungen auf dem lokalen Knoten oder im gesamten Cluster an.

Das Informationsschema

Das Informationsschema ist ein spezielles Schema in jeder Datenbank, das Metadaten über die anderen Objekte in der Datenbank enthält - in CockroachDB heißt es INFORMATION_SCHEMA. Du kannst das Informationsschema verwenden, um die Namen und Typen der Objekte in der Datenbank zu ermitteln. Du kannst das Informationsschema zum Beispiel verwenden, um alle Objekte im Schema information_schema aufzulisten:

SELECT * FROM information_schema."tables"
 WHERE table_schema='information_schema';

Oder du kannst information_schema verwenden, um die Spalten in einer Tabelle anzuzeigen:

SELECT column_name,data_type, is_nullable,column_default
 FROM information_schema.COLUMNS WHERE TABLE_NAME='customers';

Das Informationsschema ist besonders nützlich, wenn du Anwendungen für ein unbekanntes Datenmodell schreibst. GUI-Tools wie DBeaver nutzen das Informationsschema zum Beispiel, um den Datenbankbaum zu füllen und Informationen über Tabellen und Indizes anzuzeigen.

Das Informationsschema ist durch ANSI-Standards definiert und wird von vielen relationalen Datenbanken implementiert. CockroachDB enthält auch einige interne Tabellen, die speziell für das CockroachDB-System im crdb_internal Schema enthalten sind. Informationen über diese Tabellen findest du in der CockroachDB-Dokumentation.

Zusammenfassung

In diesem Kapitel haben wir die Grundlagen der SQL-Sprache zum Erstellen, Abfragen und Ändern von Daten in der CockroachDB-Datenbank besprochen.

Eine vollständige Definition aller Syntaxelemente von CockroachDB SQL würde ein ganzes Buch in Anspruch nehmen, daher haben wir uns hauptsächlich auf die Kernfunktionen der SQL-Sprache konzentriert und einige CockroachDB-spezifische Funktionen hervorgehoben. Eine ausführliche Syntax und Details zu den CockroachDB-Verwaltungsbefehlen findest du in derCockroachDB-Online-Dokumentation.

SQL ist die Sprache von CockroachDB. Natürlich werden wir die CockroachDB-SQL-Sprache weiter ausarbeiten, wenn wir tiefer in die Welt von CockroachDB eintauchen.

1 Beachte, dass user_ride_counts nicht im Standardschema rides definiert ist. Es ist definiert als SELECT u.name, COUNT(u.name) AS rides FROM "users" AS u JOIN "rides" AS r ON (u.id=r.rider_id) GROUP BY u.name .

Get CockroachDB: Der endgültige Leitfaden now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.