

Die vorliegende Übersetzung wurde maschinell erstellt. Im Falle eines Konflikts oder eines Widerspruchs zwischen dieser übersetzten Fassung und der englischen Fassung (einschließlich infolge von Verzögerungen bei der Übersetzung) ist die englische Fassung maßgeblich.

# Single-shard Abfragen in der Aurora PostgreSQL Limitless Database
<a name="limitless-query.single-shard"></a>

Eine *Single-Shard-Abfrage* ist eine Abfrage, die direkt auf einem Shard ausgeführt werden kann, wobei die SQL-[ACID](https://en.wikipedia.org/wiki/ACID)-Semantik beibehalten wird. Wenn der Abfrageplaner auf dem Router auf eine solche Abfrage trifft, erkennt der Planer sie und leitet die gesamte SQL-Abfrage an den entsprechenden Shard weiter.

Diese Optimierung reduziert die Anzahl der Netzwerk-Roundtrips vom Router zum Shard und verbessert die Leistung. Derzeit wird diese Optimierung für die Abfragen `INSERT`, `SELECT`, `UPDATE` und `DELETE` durchgeführt.

**Topics**
+ [Single-shard Beispiele für Abfragen](#limitless-query.single-shard.examples)
+ [Einschränkungen für Single-Shard-Abfragen](#limitless-query.single-shard.restrictions)
+ [Vollständig qualifizierte (explizite) Joins](#limitless-query.single-shard.fq)
+ [Festlegen eines aktiven Shard-Schlüssels](#limitless-query.single-shard.active)

## Single-shard Beispiele für Abfragen
<a name="limitless-query.single-shard.examples"></a>

Die folgenden Beispiele umfassen die Sharded-Tabelle `customers` mit dem Shard-Schlüssel `customer_id` und die Referenztabelle `zipcodes`.

**SELECT**  

```
postgres_limitless=> EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM customers WHERE customer_id = 100;

                       QUERY PLAN                        
---------------------------------------------------------
 Foreign Scan
   Output: customer_id, other_id, customer_name, balance
   Remote SQL:  SELECT customer_id,
     other_id,
     customer_name,
     balance
    FROM public.customers
   WHERE (customer_id = 100)
 Single Shard Optimized
(9 rows)
```

```
postgres_limitless=> EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM orders
    LEFT JOIN zipcodes ON orders.zipcode_id = zipcodes.zipcode_id
    WHERE customer_id = 11;

                                               QUERY PLAN                                                
---------------------------------------------------------------------------------------------------------
 Foreign Scan
   Output: customer_id, order_id, zipcode_id, customer_name, balance, zipcodes.zipcode_id, zipcodes.city
   Remote SQL:  SELECT orders.customer_id,
     orders.order_id,
     orders.zipcode_id,
     orders.customer_name,
     orders.balance,
     zipcodes.zipcode_id,
     zipcodes.city
    FROM (public.orders
      LEFT JOIN public.zipcodes ON ((orders.zipcode_id = zipcodes.zipcode_id)))
   WHERE (orders.customer_id = 11)
 Single Shard Optimized
(13 rows)
```

**INSERT**  

```
postgres_limitless=> EXPLAIN (VERBOSE, COSTS OFF) INSERT INTO customers
    (customer_id, other_id, customer_name, balance)
    VALUES (1, 10, 'saikiran', 1000);

                      QUERY PLAN                       
-------------------------------------------------------
 Insert on public.customers
   ->  Result
         Output: 1, 10, 'saikiran'::text, '1000'::real
 Single Shard Optimized
(4 rows)
```

**AKTUALISIERUNG**  

```
postgres_limitless=> EXPLAIN (VERBOSE, COSTS OFF) UPDATE orders SET balance = balance + 100
    WHERE customer_id = 100;

                                         QUERY PLAN                                          
---------------------------------------------------------------------------------------------
 Update on public.orders
   Foreign Update on public.orders_fs00002 orders_1
   ->  Foreign Update
         Remote SQL:  UPDATE public.orders SET balance = (balance + (100)::double precision)
   WHERE (customer_id = 100)
 Single Shard Optimized
(6 rows)
```

**DELETE**  

```
postgres_limitless=> EXPLAIN (VERBOSE, COSTS OFF) DELETE FROM orders
    WHERE customer_id = 100 and balance = 0;

                             QUERY PLAN                              
---------------------------------------------------------------------
 Delete on public.orders
   Foreign Delete on public.orders_fs00002 orders_1
   ->  Foreign Delete
         Remote SQL:  DELETE FROM public.orders
   WHERE ((customer_id = 100) AND (balance = (0)::double precision))
 Single Shard Optimized
(6 rows)
```

## Einschränkungen für Single-Shard-Abfragen
<a name="limitless-query.single-shard.restrictions"></a>

Single-shard Abfragen haben die folgenden Einschränkungen:

**Funktionen**  
Wenn eine Single-Shard-Abfrage eine Funktion enthält, kommt die Abfrage nur dann für die Single-Shard-Optimierung in Frage, wenn eine der folgenden Bedingungen zutrifft:  
+ Die Funktion ist unveränderlich. Weitere Informationen finden Sie unter [Funktionsvolatilität](limitless-reference.DDL-limitations.md#limitless-function-volatility).
+ Die Funktion ist veränderbar, aber in der Ansicht `rds_aurora.limitless_distributed_functions` registriert. Weitere Informationen finden Sie unter [Verteilung der Funktionen](limitless-reference.DDL-limitations.md#limitless-function-distribution).

**Ansichten**  
Wenn eine Abfrage eine oder mehrere Ansichten enthält, ist die Single-Shard-Optimierung für die Abfrage deaktiviert, wenn sie eine der folgenden Bedingungen erfüllt:  
+ Jede Ansicht hat das Attribut `security_barrier`.
+ Für die in der Abfrage verwendeten Objekte sind mehrere Benutzerberechtigungen erforderlich. Eine Abfrage enthält beispielsweise zwei Ansichten, und die Ansichten werden unter zwei verschiedenen Benutzern ausgeführt.

```
CREATE VIEW v1 AS SELECT customer_name FROM customers c WHERE c.customer_id =  1;
CREATE VIEW v2 WITH (security_barrier) AS SELECT customer_name FROM customers c WHERE c.customer_id =  1;

postgres_limitless=> EXPLAIN VERBOSE SELECT * FROM v1;
                                     QUERY PLAN
------------------------------------------------------------------------------------
 Foreign Scan  (cost=100.00..101.00 rows=100 width=0)
   Output: customer_name
   Remote Plans from Shard postgres_s3:
         Seq Scan on public.customers_ts00001 c  (cost=0.00..24.12 rows=6 width=32)
           Output: c.customer_name
           Filter: (c.customer_id = 1)
         Query Identifier: -6005737533846718506
   Remote SQL:  SELECT customer_name
    FROM ( SELECT c.customer_name
            FROM public.customers c
           WHERE (c.customer_id = 1)) v1
 Query Identifier: -5754424854414896228
(12 rows)


postgres_limitless=> EXPLAIN VERBOSE SELECT * FROM v2;
                                         QUERY PLAN
--------------------------------------------------------------------------------------------
 Foreign Scan on public.customers_fs00001 c  (cost=100.00..128.41 rows=7 width=32)
   Output: c.customer_name
   Remote Plans from Shard postgres_s3:
         Seq Scan on public.customers_ts00001 customers  (cost=0.00..24.12 rows=6 width=32)
           Output: customers.customer_name
           Filter: (customers.customer_id = 1)
         Query Identifier: 4136563775490008117
   Remote SQL: SELECT customer_name FROM public.customers WHERE ((customer_id = 1))
 Query Identifier: 5056054318010163757
(9 rows)
```

**Anweisungen PREPARE und EXECUTE**  
Aurora PostgreSQL Limitless Database unterstützt die Single-Shard-Optimierung für vorbereitete `SELECT`-, `UPDATE`- und `DELETE`-Anweisungen.  
Wenn Sie jedoch vorbereitete Anweisungen für `PREPARE` und `EXECUTE` verwenden und `plan_cache_mode` dabei auf `'force_generic_plan'` festgelegt haben, lehnt der Abfrageplaner die Single-Shard-Optimierung für diese Abfrage ab. 

**PL/pgSQL**  
Abfragen mit PL/pgSQL Variablen werden als implizit vorbereitete Anweisungen ausgeführt. Wenn eine Abfrage PL/pgSQL Variablen enthält, lehnt der Abfrageplaner die Single-Shard-Optimierung ab.  
Die Optimierung wird im PL/pgSQL Block unterstützt, wenn die Anweisung keine Variablen enthält. PL/pgSQL 

## Vollständig qualifizierte (explizite) Joins
<a name="limitless-query.single-shard.fq"></a>

Single-shard Die Optimierung basiert auf der Eliminierung von Partitionen. Der PostgreSQL-Optimierer eliminiert Partitionen auf der Grundlage konstanter Bedingungen. Wenn Aurora PostgreSQL Limitless Database feststellt, dass sich alle verbleibenden Partitionen und Tabellen auf demselben Shard befinden, markiert sie die Abfrage, die für die Single-Shard-Optimierung in Frage kommt. Alle Filterbedingungen müssen explizit sein, damit das Eliminieren von Partitionen funktioniert. Aurora PostgreSQL Limitless Database kann Partitionen ohne ein oder mehrere Join- oder Filterprädikate in den Shard-Schlüsseln jeder Sharded-Tabelle in der Anweisung nicht eliminieren.

Gehen Sie davon aus, dass wir die Tabellen `customers`, `orders` und `order_details` auf Grundlage der Spalte `customer_id` partitioniert haben. In diesem Schema versucht die Anwendung, alle Daten für einen Kunden auf einem einzigen Shard zu speichern.

Betrachten Sie folgende Abfrage:

```
SELECT * FROM 
    customers c, orders o, order_details od 
WHERE c.customer_id = o.customer_id
    AND od.order_id = o.order_id
    AND c.customer_id = 1;
```

Diese Abfrage ruft alle Daten für einen Kunden (`c.customer_id = 1`) ab. Die Daten für diesen Kunden befinden sich auf einem einzigen Shard, aber Aurora PostgreSQL Limitless Database qualifiziert diese Abfrage nicht als Single-Shard-Abfrage. Der Optimierungsprozess für die Abfrage sieht wie folgt aus:

1. Der Optimierer kann Partitionen für `customers` und `orders` auf Grundlage der folgenden Bedingung entfernen:

   ```
   c.customer_id = 1
   c.customer_id = o.customer_id
   o.customer_id =  1 (transitive implicit condition)
   ```

1. Der Optimierer kann keine Partitionen für `order_details` eliminieren, da es in der Tabelle keine konstante Bedingung gibt.

1. Der Optimierer kommt zu dem Schluss, dass er alle Partitionen aus `order_details` gelesen hat. Daher kann die Abfrage nicht für die Single-Shard-Optimierung qualifiziert werden.

Um sie zu einer Single-Shard-Abfrage zu machen, fügen wir die folgende explizite Join-Bedingung hinzu:

```
o.customer_id = od.customer_id
```

Die geänderte Abfrage sieht wie folgt aus:

```
SELECT * FROM 
    customers c, orders o,  order_details od 
WHERE c.customer_id = o.customer_id
     AND o.customer_id = od.customer_id
     AND od. order_id = o. order_id
 AND c.customer_id =  1;
```

Jetzt kann der Optimierer Partitionen für `order_details` eliminieren. Die neue Abfrage wird zu einer Single-Shard-Abfrage und ist für die Optimierung geeignet.

## Festlegen eines aktiven Shard-Schlüssels
<a name="limitless-query.single-shard.active"></a>

Mit diesem Feature können Sie bei der Abfrage der Datenbank einen einzelnen Shard-Schlüssel festlegen, wodurch an alle `SELECT`- und DML-Abfragen der Shard-Schlüssel als konstantes Prädikat angehängt wird. Diese Funktion ist nützlich, wenn Sie eine Migration zu Aurora PostgreSQL Limitless Database durchgeführt und das Schema durch Hinzufügen von Shard-Schlüsseln zu Tabellen denormalisiert haben.

Sie können ein Shard-Schlüsselprädikat automatisch an die bestehende SQL-Logik anhängen, ohne die Semantik der Abfragen zu ändern. Das Anhängen eines aktiven Shard-Schlüsselprädikats erfolgt nur für [kompatible Tabellen](#active-shard-key-compatible-tables).

Das Feature Aktiver Shard-Schlüssel verwendet die Variable `rds_aurora.limitless_active_shard_key`, die die folgende Syntax hat:

```
SET [session | local] rds_aurora.limitless_active_shard_key = '{"col1_value", "col2_value", ...}';
```

Einige Überlegungen zu aktiven Shard-Schlüsseln und Fremdschlüsseln:
+ Für eine Sharded-Tabelle kann eine Fremdschlüsselbeschränkung gelten, wenn die übergeordneten und untergeordneten Tabellen nebeneinander angeordnet sind und der Fremdschlüssel eine Obermenge des Shard-Schlüssels bildet.
+ Für eine Sharded-Tabelle kann eine Fremdschlüsselbeschränkung hinsichtlich einer Referenztabelle gelten.
+ Für eine Referenztabelle kann eine Fremdschlüsselbeschränkung hinsichtlich einer anderen Referenztabelle gelten.

Nehmen wir an, wir haben eine `customers`-Tabelle mit angewendetem Sharding in der Spalte `customer_id`.

```
BEGIN;
SET local rds_aurora.limitless_create_table_mode='sharded';
SET local rds_aurora.limitless_create_table_shard_key='{"customer_id"}';
CREATE TABLE customers(customer_id int PRIMARY KEY, name text , email text);
COMMIT;
```

 Bei einem aktiven Shard-Schlüsselsatz weisen Abfragen die folgenden Transformationen auf.

**SELECT**  

```
SET rds_aurora.limitless_active_shard_key = '{"123"}';
SELECT * FROM customers;

-- This statement is changed to:
SELECT * FROM customers WHERE customer_id = '123'::int;
```

**INSERT**  

```
SET rds_aurora.limitless_active_shard_key = '{"123"}';
INSERT INTO customers(name, email) VALUES('Alex', 'alex@example.com');

-- This statement is changed to:
INSERT INTO customers(customer_id, name, email) VALUES('123'::int, 'Alex', 'alex@example.com');
```

**AKTUALISIERUNG**  

```
SET rds_aurora.limitless_active_shard_key = '{"123"}';
UPDATE customers SET email = 'alex_new_email@example.com';

-- This statement is changed to:
UPDATE customers SET email = 'alex_new_email@example.com' WHERE customer_id = '123'::int;
```

**DELETE**  

```
SET rds_aurora.limitless_active_shard_key = '{"123"}';
DELETE FROM customers;

-- This statement is changed to:
DELETE FROM customers WHERE customer_id = '123'::int;
```

**Joins**  
Wenn an Tabellen mit einem aktiven Shard-Schlüssel Join-Operationen ausgeführt werden, wird das Shard-Schlüssel-Prädikat automatisch allen an der Verknüpfung beteiligten Tabellen hinzugefügt. Dieses automatische Hinzufügen des Shard-Schlüssel-Prädikats erfolgt nur, wenn alle Tabellen in der Abfrage derselben Kollokationsgruppe angehören. Wenn die Abfrage Tabellen aus verschiedenen Kollokationsgruppen umfasst, wird stattdessen ein Fehler ausgelöst.  
Gehen Sie davon aus, dass wir auch über `orders`- und `order_details`-Tabellen verfügen, die mit der `customers`-Tabelle zusammengefasst sind.  

```
SET local rds_aurora.limitless_create_table_mode='sharded';
SET local rds_aurora.limitless_create_table_collocate_with='customers';
SET local rds_aurora.limitless_create_table_shard_key='{"customer_id"}';
CREATE TABLE orders (id int , customer_id int, total_amount int, date date);
CREATE TABLE order_details (id int , order_id int, customer_id int, product_name VARCHAR(100), price int);
COMMIT;
```
Hier rufen wir die letzten 10 Bestellrechnungen für einen Kunden ab, dessen Kundennummer 10 ist.  

```
SET rds_aurora.limitless_active_shard_key = '{"10"}';
SELECT * FROM customers, orders, order_details WHERE
    orders.customer_id = customers.customer_id AND
    order_details.order_id = orders.order_id AND
    customers.customer_id = 10
    order by order_date limit 10;
```
Diese Abfrage wird in Folgende transformiert:  

```
SELECT * FROM customers, orders, order_details WHERE
    orders.customer_id = customers.customer_id AND
    orders.order_id = order_details.order_id AND
    customers.customer_id = 10 AND
    order_details.customer_id = 10 AND
    orders.customer_id = 10 AND
    ORDER BY "order_date" LIMIT 10;
```

**Tabellen, die mit aktiven Shard-Schlüsseln kompatibel sind**  
Das Shard-Schlüssel-Prädikat wird nur zu Tabellen hinzugefügt, die mit dem aktiven Shard-Schlüssel kompatibel sind. Eine Tabelle gilt als kompatibel, wenn ihr Shard-Schlüssel genau die Anzahl von Spalten enthält, die in der Variablen `rds_aurora.limitless_active_shard_key` angegeben ist. Wenn die Abfrage Tabellen umfasst, die nicht mit dem aktiven Shard-Schlüssel kompatibel sind, gibt das System einen Fehler aus, anstatt mit der Abfrage fortzufahren.  
Beispiel:  

```
-- Compatible table
SET rds_aurora.limitless_active_shard_key = '{"10"}';

-- The following query works because the customers table is sharded on one column.
SELECT * FROM customers;
  
-- Incompatible table
SET rds_aurora.limitless_active_shard_key = '{"10","20"}';

-- The following query raises a error because the customers table isn't sharded on two columns.
 SELECT * FROM customers;
```