Vorbereiten von Datendateien¶
Dieses Thema enthält bewährte Verfahren, allgemeine Richtlinien und wichtige Hinweise für die Vorbereitung Ihrer Datendateien zum Laden.
Unter diesem Thema:
Best Practices und Einschränkungen für Dateigrößen¶
Beachten Sie für eine optimale Ladeleistung und zur Vermeidung von Größenbeschränkungen die folgenden Richtlinien für die Dimensionierung von Dateien. Beachten Sie, dass diese Empfehlungen sowohl für das Laden von Massendaten als auch für das kontinuierliche Laden mit Snowpipe gelten.
Allgemeine Empfehlungen für Dateigrößen¶
Die Anzahl der parallel laufenden Operationen darf die Anzahl der zu ladenden Datendateien nicht überschreiten. Um die Anzahl der parallelen Operationen für das Laden zu optimieren, empfehlen wir, Datendateien mit einer komprimierten Größe von 100–250 MB zu erstellen.
Bemerkung
Das Laden sehr großer Dateien (z. B. 100 GB oder größer) wird nicht empfohlen.
Wenn Sie eine große Datei laden müssen, sollten Sie den Wert der Kopieroption ON_ERROR sorgfältig prüfen. Der Abbruch oder das Überspringen einer Datei aufgrund einer geringen Anzahl von Fehlern kann zu Verzögerungen und verschwendeten Credits führen. Wenn eine Datenladeoperation über die maximal zulässige Dauer von 24 Stunden hinaus andauert, kann sie außerdem abgebrochen werden, ohne dass die Übertragung von Teilen der Datei bestätigt (Commit) wird.
Fassen Sie kleinere Dateien zusammen, um den Verarbeitungsaufwand für jede Datei zu minimieren. Teilen Sie große Dateien in eine größere Anzahl kleinerer Dateien auf, um die Last auf die Computeressourcen des aktiven Warehouses zu verteilen. Die Anzahl der Datendateien, die parallel verarbeitet werden, wird durch die Anzahl der Computeressourcen in einem Warehouse bestimmt. Wir empfehlen ein zeilenweises Aufteilen der Dateien, um Datensätze zu vermeiden, die sich über Blöcke verteilen.
Wenn Ihre Quelldatenbank es Ihnen nicht erlaubt, Datendateien in kleineren Blöcken zu exportieren, können Sie das Dienstprogramm eines Drittanbieters verwenden, um große CSV-Dateien aufzuteilen.
Linux oder macOS¶
Das Dienstprogramm split
ermöglicht es Ihnen, eine CSV-Datei in mehrere kleinere Dateien aufzuteilen.
Syntax:
split [-a suffix_length] [-b byte_count[k|m]] [-l line_count] [-p pattern] [file [name]]
Weitere Informationen erhalten Sie, wenn Sie man split
in ein Terminalfenster eingeben.
Beispiel:
split -l 100000 pagecounts-20151201.csv pages
In diesem Beispiel wird eine Datei mit dem Namen pagecounts-20151201.csv
nach Zeilenlänge aufgeteilt. Angenommen, die große einzelne Datei ist 8 GB groß und enthält 10 Millionen Zeilen. Geteilt durch 100.000, ist jede der 100 kleineren Dateien 80 MB groß (10 Millionen / 100.000 = 100). Die aufgeteilten Dateien haben den Namen pagessuffix
.
Windows¶
Windows enthält kein natives Dienstprogramm zur Dateiaufteilung; Windows unterstützt jedoch viele Tools und Skripte von Drittanbietern, die große Datendateien aufteilen können.
Verkleinern der Größe von Objekten, die größer als 16 MB sind, vor dem Laden¶
Bemerkung
Um dieses Feature nutzen zu können, müssen Sie das Verhaltensänderungs-Bundle 2024_08 in Ihrem Konto aktivieren.
Zum Aktivieren dieses Bundles in Ihrem Konto führen Sie die folgende Anweisung aus:
SELECT SYSTEM$ENABLE_BEHAVIOR_CHANGE_BUNDLE('2024_08');
Ein Fehler tritt auf, wenn Sie versuchen, ein Objekt, das größer als 16 MB ist, aus einer Datei im Stagingbereich in eine der folgenden Spaltentypen zu laden:
VARCHAR (einschließlich der Typen, die gleichbedeutend mit VARCHAR sind)
BINARY (einschließlich der Typen, die gleichbedeutend mit BINARY sind)
VARIANT
OBJECT
ARRAY
GEOGRAPHY
GEOMETRY
Der folgende Fehler tritt auf, weil die maximale Größe eines Objekts, das in einer Spalte gespeichert ist, 16 MB beträgt:
Max LOB size (16777216) exceeded
In der Vergangenheit trat dieser Fehler auch auf, wenn versucht wurde, eine Datei auf einem Stagingbereich abzufragen, und die Datei Objekte enthielt, die größer als 16 MB waren.
Auch wenn Sie immer noch keine Objekte, die größer als 16 MB sind, in einer Spalte speichern können, können Sie jetzt Objekte bis zu 128 MB in Dateien im Stagingbereich abfragen. Sie können dann die Größe der Objekte reduzieren, bevor Sie die Objekte in Spalten speichern. Es tritt kein Fehler mehr auf, wenn Sie eine Datei abfragen, die Objekte enthält, die größer als 16 MB aber kleiner als 128 MB sind.
So können Sie beispielsweise große Objekte auf mehrere Spalten oder Zeilen aufteilen, verschachteltes JSON in ein tabellarisches Format umwandeln oder komplexe Geometrien vereinfachen.
Beispiel: Laden einer großen JSON-Datei in separate Zeilen¶
Im Allgemeinen sind JSON-Datasets eine einfache Verkettung mehrerer Dokumente. Die JSON-Ausgabe einer Software besteht aus einem einzigen großen Array, das mehrere Datensätze enthält. Sie müssen die Dokumente nicht durch Zeilenumbrüche oder Kommas trennen, aber beides wird unterstützt.
Wenn der Datenumfang größer 16 MB ist, aktivieren Sie die Dateiformatoption STRIP_OUTER_ARRAY für den Befehl COPY INTO <Tabelle>, um die äußere Array-Struktur zu entfernen und die Datensätze in separate Tabellenzeilen zu laden:
COPY INTO <table>
FROM @~/<file>.json
FILE_FORMAT = (TYPE = 'JSON' STRIP_OUTER_ARRAY = true);
Beispiel: Laden und Teilen von JSON-Objekten aus einer Parquet-Datei¶
Angenommen, Sie laden eine Parquet-Datei aus einem Stagingbereich und die Parquet-Datei enthält ein JSON-Objekt, das größer als 16 MB ist:
{
"ID": 1,
"CustomerDetails": {
"RegistrationDate": 158415500,
"FirstName": "John",
"LastName": "Doe",
"Events": [
{
"Type": "LOGIN",
"Time": 1584158401,
"EventID": "NZ0000000001"
},
/* ... */
/* this array contains thousands of elements */
/* with total size exceeding 16 MB */
/* ... */
{
"Type": "LOGOUT",
"Time": 1584158402,
"EventID": "NZ0000000002"
}
]
}
}
Das folgende Beispiel erstellt eine Tabelle zum Speichern der Daten aus der Datei und lädt die Daten in die Tabelle. Da die Größe des Arrays von Ereignissen 16 MB überschreiten kann, wird das Array von Ereignissen im Beispiel in separate Zeilen (eine für jedes Element des Arrays) aufgeteilt.
CREATE OR REPLACE TABLE mytable AS
SELECT
t1.$1:ID AS id,
t1.$1:CustomerDetails:RegistrationDate::VARCHAR AS RegistrationDate,
t1.$1:CustomerDetails:FirstName::VARCHAR AS First_Name,
t1.$1:CustomerDetails:LastName::VARCHAR AS as Last_Name,
t2.value AS Event
FROM @json t1,
TABLE(FLATTEN(INPUT => $1:CustomerDetails:Events)) t2;
Im Folgenden sehen Sie ein Beispiel für den Inhalt der resultierenden Tabelle.
+----+-------------------+------------+------------+------------------------------+
| ID | REGISTRATION_DATE | FIRST_NAME | LAST_NAME | EVENT |
|----+-------------------+------------+------------+------------------------------|
| 1 | 158415500 | John | Doe | { |
| | | | | "EventID": "NZ0000000001", |
| | | | | "Time": 1584158401, |
| | | | | "Type": "LOGIN" |
| | | | | } |
| ... thousands of rows ... |
| 1 | 158415500 | John | Doe | { |
| | | | | "EventID": "NZ0000000002", |
| | | | | "Time": 1584158402, |
| | | | | "Type": "LOGOUT" |
| | | | | } |
+----+-------------------+------------+------------+------------------------------+
Einfügen von FLATTEN-Ergebnissen in eine bestehende Tabelle¶
Um die Ergebnisse der Funktion FLATTEN in eine vorhandene Tabelle einzufügen, verwenden Sie eine INSERT-Anweisung. Beispiel:
CREATE OR REPLACE TABLE mytable (
id VARCHAR,
registration_date VARCHAR(16777216),
first_name VARCHAR(16777216),
last_name VARCHAR(16777216),
event VARCHAR(16777216));
INSERT INTO mytable
SELECT
t1.$1:ID,
t1.$1:CustomerDetails:RegistrationDate::VARCHAR,
t1.$1:CustomerDetails:FirstName::VARCHAR,
t1.$1:CustomerDetails:LastName::VARCHAR,
t2.value
FROM @json t1,
TABLE(FLATTEN(INPUT => $1:CustomerDetails:Events)) t2;
Beispiel: Laden und Teilen XML¶
Angenommen, Sie laden eine XML-Datei aus einem Stagingbereich und diese enthält ein Objekt XML, das größer als 16 MB ist:
<?xml version='1.0' encoding='UTF-8'?>
<osm version="0.6" generator="osmium/1.14.0">
<node id="197798" version="17" timestamp="2021-09-06T17:01:27Z" />
<node id="197824" version="7" timestamp="2021-08-04T23:17:18Z" >
<tag k="highway" v="traffic_signals"/>
</node>
<!-- thousands of node elements with total size exceeding 16 MB -->
<node id="197826" version="4" timestamp="2021-08-04T16:43:28Z" />
</osm>
Das folgende Beispiel erstellt eine Tabelle zum Speichern der Daten aus der Datei und lädt die Daten in die Tabelle. Da die Größe der XML-Datei 16 MB überschreiten kann, wird in diesem Beispiel jede node
in separate Zeilen aufgeteilt.
CREATE OR REPLACE TABLE mytable AS
SELECT
value:"@id" AS id,
value:"@version" AS version,
value:"@timestamp"::datetime AS TIMESTAMP,
value:"$" AS tags
FROM @mystage,
LATERAL FLATTEN(INPUT => $1:"$")
WHERE value:"@" = 'node';
Im Folgenden sehen Sie ein Beispiel für den Inhalt der resultierenden Tabelle.
+--------+---------+-------------------------+---------------------------------------------+
| ID | VERSION | TIMESTAMP | TAGS |
|--------+---------+-------------------------+---------------------------------------------|
| 197798 | 17 | 2021-09-06 17:01:27.000 | "" |
| 197824 | 7 | 2021-08-04 23:17:18.000 | <tag k="highway" v="traffic_signals"></tag> |
| ... thousands of rows ... |
| 197826 | 4 | 2021-08-04 16:43:28.000 | "" |
+--------+---------+-------------------------+---------------------------------------------+
Beispiel: Laden und Vereinfachen großer Geodatenobjekte vor dem Speichern¶
Angenommen, Sie laden eine Parquet-Datei aus einem Stagingbereich, und die Parquet-Datei enthält ein Geodatenobjekt, das größer als 16 MB ist. Sie können die Datei aus dem Stagingbereich laden und das Geodatenbjekt vereinfachen (indem Sie ST_SIMPLIFY verwenden), bevor Sie das Objekt speichern:
CREATE OR REPLACE TABLE mytable AS
SELECT
ST_SIMPLIFY($1:geo, 10) AS geo
FROM @mystage;
Beispiel: Verwendung von COPY INTO <Tabelle>¶
Wenn Sie COPY INTO <Tabelle> verwenden müssen, um Daten aus einer Datei in einen Stagingbereich zu laden, können Sie FLATTEN nicht verwenden, um große Objekte aufzuteilen. Verwenden Sie stattdessen SELECT. Beispiel:
CREATE OR REPLACE TABLE mytable (
id VARCHAR,
registration_date VARCHAR,
first_name VARCHAR,
last_name VARCHAR);
COPY INTO mytable (
id,
registration_date,
first_name,
last_name
) FROM (
SELECT
$1:ID,
$1:CustomerDetails::OBJECT:RegistrationDate::VARCHAR,
$1:CustomerDetails::OBJECT:FirstName::VARCHAR,
$1:CustomerDetails::OBJECT:LastName::VARCHAR
FROM @mystage
);
Kontinuierliches Laden von Daten (d. h. Snowpipe) und Dateigrößen¶
Snowpipe wurde entwickelt, um neue Daten typischerweise innerhalb einer Minute nach dem Senden einer Dateibenachrichtigung zu laden. Das Laden kann jedoch bei wirklich großen Dateien erheblich länger dauern oder in Fällen, in denen eine ungewöhnliche Menge an Computeressourcen erforderlich ist, um die neuen Daten zu dekomprimieren, zu entschlüsseln und zu transformieren.
Zusätzlich zum Ressourcenverbrauch sind Betriebskosten für die Verwaltung von Dateien in der internen Ladewarteschlange in den Nutzungskosten für Snowpipe enthalten. Dieser Overhead steigt in Abhängigkeit von der Anzahl der Dateien, die der Warteschlange zum Laden hinzugefügt werden. Diese Overhead-Kosten erscheinen auf der Abrechnung als Snowpipe-Gebühren, da Snowpipe für die Ereignisbenachrichtigungen bei der automatischen Aktualisierung der externen Tabellen verwendet wird.
Für ein möglichst effizientes und kostengünstiges Laden mit Snowpipe wird empfohlen, die unter Best Practices und Einschränkungen für Dateigrößen (unter diesem Thema) bereitgestellten Empfehlungen zur Dateigröße zu befolgen. Das Laden von Datendateien, die etwa 100-250 MB oder größer sind, reduziert die Overhead-Kosten im Verhältnis zur Menge der insgesamt bis zu dem Punkt geladenen Daten, an dem die Overhead-Kosten unerheblich werden.
Wenn es länger als eine Minute dauert, MBs von Daten in Ihrer Quellanwendung zusammenzufassen, sollten Sie erwägen, einmal pro Minute eine neue (möglicherweise kleinere) Datendatei zu erstellen. Dieser Ansatz führt in der Regel zu einem ausgewogenen Verhältnis zwischen Kosten (d. h. Ressourcen, die für die Verwaltung der Snowpipe-Warteschlange und den eigentlichen Ladevorgang benötigt werden) und Leistung (d. h. Latenzzeit beim Laden).
Das Erstellen von kleineren Datendateien und deren Staging im Cloudspeicher häufiger als einmal pro Minute hat folgende Nachteile:
Eine Verkürzung der Latenzzeit zwischen Staging und Laden von Daten kann nicht garantiert werden.
Die Betriebskosten für die Verwaltung von Dateien in der internen Ladewarteschlange sind in den Nutzungskosten für Snowpipe enthalten. Diese Verwaltungskosten steigen in Abhängigkeit von der Anzahl der Dateien, die zum Laden in die Warteschlange eingefügt werden.
Verschiedene Tools können Datendateien aggregieren und stapeln. Eine praktische Option ist Amazon Data Firehose. Firehose ermöglicht es, sowohl die gewünschte Dateigröße, die sogenannte Puffergröße, als auch das Warteintervall zu definieren, nach dem eine neue Datei gesendet wird (in diesem Fall an den Cloudspeicher), das sogenannte Pufferintervall. Weitere Informationen dazu finden Sie in der Amazon Data Firehose-Dokumentation. Wenn Ihre Quellanwendung normalerweise innerhalb einer Minute genug Daten sammelt, um Dateien zu füllen, die über dem empfohlenen Maximum für eine optimale Parallelverarbeitung liegen, können Sie die Puffergröße verringern, um die Bereitstellung kleinerer Dateien auszulösen. Wenn Sie die Einstellung des Pufferintervalls bei 60 Sekunden (dem Minimalwert) belassen, vermeiden Sie, zu viele Dateien zu erstellen oder die Latenzzeit zu erhöhen.
Vorbereiten von durch Trennzeichen getrennten Textdateien¶
Beachten Sie die folgenden Richtlinien, wenn Sie Dateien mit durch Trennzeichen getrenntem Text (CSV) zum Laden vorbereiten:
UTF-8 ist der Standardzeichensatz, es werden jedoch auch zusätzliche Codierungen unterstützt. Verwenden Sie die Dateiformatoption ENCODING, um den Zeichensatz für die Datendateien festzulegen. Weitere Informationen dazu finden Sie unter CREATE FILE FORMAT.
Felder, die Trennzeichen enthalten, sollten in Anführungszeichen (einfach oder doppelt) gesetzt werden. Wenn die Daten einfache oder doppelte Anführungszeichen enthalten, müssen diese Anführungszeichen in Escape-Zeichen eingeschlossen werden.
Zeilenumbrüche werden auf Windows-Systemen häufig in Verbindung mit einem Zeilenvorschubzeichen verwendet, um das Ende einer Zeile zu markieren (
\r \n
). Felder, die Zeilenumbrüche enthalten, sollten ebenfalls in Anführungszeichen (einfach oder doppelt) gesetzt werden.Die Anzahl der Spalten in jeder Zeile sollte konsistent sein.
Semistrukturierte Datendateien und Spaltenbildung¶
Wenn semistrukturierte Daten in eine VARIANT-Spalte eingefügt werden, verwendet Snowflake bestimmte Regeln, um so viele der Daten wie möglich in eine spaltenweise Form zu extrahieren. Der Rest der Daten wird als eine einzige Spalte in einer geparsten, semistrukturierten Struktur gespeichert.
Standardmäßig extrahiert Snowflake maximal 200 Elemente pro Partition und Tabelle. Wenn Sie dieses Limit erhöhen möchten, wenden Sie sich an den Snowflake-Support.
Elemente, die nicht extrahiert werden¶
Elemente mit den folgenden Eigenschaften werden nicht in eine Spalte extrahiert:
Elemente, die auch nur einen einzigen „null“-Wert enthalten, werden nicht in eine Spalte extrahiert. Beachten Sie, dass dies für Elemente mit „Null“-Werten gilt und nicht für Elemente mit fehlenden Werten, die in Spaltenform dargestellt werden.
Diese Regel stellt sicher, dass keine Informationen verloren gehen (d. h., dass der Unterschied zwischen VARIANT-„null“-Werten und SQL-NULL-Werten erhalten bleibt).
Elemente, die verschiedene Datentypen enthalten. Beispiel:
Das
foo
-Element in einer Zeile enthält eine Nummer:{"foo":1}
Das gleiche Element in einer anderen Zeile enthält eine Zeichenfolge:
{"foo":"1"}
Auswirkung der Extraktion auf Abfragen¶
Wenn Sie ein semistrukturiertes Element abfragen, verhält sich die Ausführungs-Engine von Snowflake unterschiedlich, je nachdem, ob ein Element extrahiert wurde.
Wenn das Element in eine Spalte extrahiert wurde, wird nur die extrahierte Spalte durchsucht.
Wenn das Element nicht in eine Spalte extrahiert wurde, muss die Engine die gesamte JSON-Struktur scannen und dann für jede Zeile die Struktur durchlaufen, um Werte auszugeben. Dies hat Auswirkungen auf die Verarbeitungsleistung.
Um die Auswirkungen auf die Leistung für nicht extrahierte Elemente zu vermeiden, gehen Sie wie folgt vor:
Extrahieren Sie semistrukturierte Datenelemente, die „null“-Werte enthalten, in relationale Spalten, bevor Sie sie laden.
Wenn die „null“-Werte in Ihren Dateien fehlende Werte anzeigen und keine andere besondere Bedeutung haben, empfehlen wir Ihnen, beim Laden von Dateien mit semistrukturierten Daten die Dateiformatoption STRIP_NULL_VALUES auf TRUE zu setzen. Mit dieser Option werden OBJECT-Elemente oder ARRAY-Elemente, die „null“-Werte enthalten, entfernt.
Stellen Sie sicher, dass jedes einzelne Element Werte eines einzigen Datentyps speichert, der dem Format eigen ist (z. B. Zeichenfolge oder Zahl für JSON).
Richtlinien für numerische Daten¶
Vermeiden Sie eingebettete Zeichen wie Kommas (z. B.
123,456
).Wenn eine Zahl eine gebrochene Komponente enthält, sollte sie vom gesamten Zahlenabschnitt durch einen Dezimalpunkt getrennt werden (z. B.
123456.789
).Nur Oracle. Die Oracle-Typen NUMBER oder NUMERIC erlauben eine beliebige Dezimalstellenzahl, d. h. sie akzeptieren Werte mit dezimalen Komponenten, auch wenn der Datentyp nicht mit einer Genauigkeit oder Dezimalstellenzahl definiert wurde. In Snowflake hingegen müssen Spalten, die für Werte mit Dezimalkomponenten ausgelegt sind, mit einer Dezimalstellenzahl definiert werden, um den Dezimalanteil zu erhalten.
Richtlinien für Datums- und Zeitstempel-Daten¶
Weitere Informationen zu den unterstützten Formaten für Datums-, Uhrzeit- und Zeitstempeldaten finden Sie unter Eingabe- und Ausgabeformate für Datum und Uhrzeit.
Nur Oracle. Der Oracle-Datentyp DATE kann Datums- oder Zeitstempelinformationen enthalten. Wenn Ihre Oracle-Datenbank DATE-Spalten enthält, die auch zeitbezogene Informationen speichern, ordnen Sie diese Spalten in Snowflake einem TIMESTAMP-Datentyp statt DATE zu.
Bemerkung
Snowflake überprüft Zeitdatenwerte zum Zeitpunkt des Ladevorgangs. Ungültige Werte für Datum, Uhrzeit und Zeitstempel (z. B. 0000-00-00
) führen zu einem Fehler.