Pushdown-Optimierung und Datensichtbarkeit

Mithilfe der Pushdown-Optimierung kann Snowflake die Abfrageverarbeitung über das Filtern von Zeilen schneller und effizienter gestalten. Die Art und Weise, wie die Filter mit Pushdown neu geordnet werden, kann jedoch zur Offenlegung von Daten führen, die nicht sichtbar sein sollen.

Unter diesem Thema wird das Pushdown-Feature beschrieben und wie dabei sensible Daten offengelegt werden könnten. Um zu verhindern, dass sensible Daten sichtbar werden, können Sie einen UDF wie unter Schutz sensibler Informationen mit sicheren UDFs und gespeicherten Prozeduren beschrieben sichern.

Unter diesem Thema:

Was ist Pushdown?

Pushdown verbessert die Leistung, indem nicht benötigte Zeilen während der Abfrageverarbeitung so früh wie möglich herausgefiltert werden. Pushdown kann auch den Speicherverbrauch reduzieren. Durch Pushdown können vertrauliche Daten jedoch indirekt angezeigt werden.

Betrachten Sie die folgende Abfrage:

SELECT col1
  FROM tab1
  WHERE location = 'New York';

Ein Ansatz zur Bearbeitung der Abfrage ist folgender:

  1. Lesen Sie alle Zeilen aus der Tabelle in den Speicher (d. h. führen Sie die FROM-Klausel aus).

  2. Scannen Sie die Zeilen im Speicher und filtern Sie alle Zeilen heraus, die nicht mit New York übereinstimmen (d. h. führen Sie die WHERE-Klausel aus).

  3. Wählen Sie col1 aus den noch im Speicher verbleibenden Zeilen aus (d. h. führen Sie die Liste SELECT aus).

Man kann sich das als eine „Erst laden, dann filtern“-Strategie vorstellen, die einfach, aber ineffizient ist.

Es ist normalerweise effizienter, so früh wie möglich zu filtern. Frühes Filtern bedeutet, „den Filter tiefer in den Abfrageplan hineinzudrücken“ oder einfach „Pushdown“.

In der Beispielabfrage oben wäre es effizienter, dem Tabellensuchcode mitzuteilen, dass keine Datensätze geladen werden sollen, die nicht mit der WHERE-Klausel übereinstimmen. Dies spart keine Filterzeit (die Position jeder Zeile muss immer noch einmal gelesen werden), kann jedoch beträchtlichen Speicherplatz sparen und die nachfolgende Verarbeitungszeit reduzieren, da weniger Zeilen verarbeitet werden müssen.

In manchen Fällen können Sie die Daten noch effizienter verarbeiten. Nehmen Sie beispielsweise an, dass die Daten nach Bundesstaat partitioniert sind (d. h. alle Daten für New York befinden sich in einer Mikropartition, alle Daten für Florida in einer anderen Mikropartition usw.). In diesem Szenario:

  • Snowflake muss nicht alle Zeilen im Speicher speichern.

  • Snowflake muss nicht alle Zeilen lesen.

Wir definieren dies lose als eine andere Form des „Pushdowns“.

Das Prinzip des „Hineindrücken der Filter“ gilt für eine Vielzahl von Abfragen. Häufig wird der Filter, der am selektivsten ist (die meisten Daten aussortiert), am tiefsten hineingedrückt (frühestens ausgeführt), um die Arbeit zu reduzieren, die die verbleibende Abfrage erledigen muss.

Pushdown kann mit anderen Techniken kombiniert werden, wie z. B. Clustering (Sortieren der Daten), um die Menge an irrelevanten Daten zu reduzieren, die gelesen, geladen und verarbeitet werden müssen.

Beispiel für indirekte Datenexposition durch Pushdown

Das folgende Beispiel zeigt eine Möglichkeit, wie Pushdown indirekt dazu führen kann, dass die zugrunde liegenden Details einer Abfrage angezeigt werden. Dieses Beispiel konzentriert sich auf Ansichten. Die gleichen Prinzipien gelten jedoch für UDFs.

Angenommen, es gibt eine Tabelle, in der Informationen zu Patienten gespeichert werden:

CREATE TABLE patients
  (patient_ID INTEGER,
   category VARCHAR,      -- 'PhysicalHealth' or 'MentalHealth'
   diagnosis VARCHAR
   );

INSERT INTO patients (patient_ID, category, diagnosis) VALUES
  (1, 'MentalHealth', 'paranoia'),
  (2, 'PhysicalHealth', 'lung cancer');

Es gibt zwei Ansichten, von denen eine Informationen zur psychischen Gesundheit und die andere Informationen zur körperlichen Gesundheit enthält:

CREATE VIEW mental_health_view AS
  SELECT * FROM patients WHERE category = 'MentalHealth';

CREATE VIEW physical_health_view AS
  SELECT * FROM patients WHERE category = 'PhysicalHealth';

Die meisten Benutzer haben keinen direkten Zugriff auf die Tabelle. Benutzern wird stattdessen eine von zwei Rollen zugewiesen:

  • MentalHealth, die über Berechtigungen zum Lesen von mental_health_view verfügt, oder

  • PhysicalHealth, die über Berechtigungen zum Lesen von physical_health_view verfügt.

Nehmen wir nun an, dass ein Arzt, der nur über Berechtigungen auf Daten zur körperlichen Gesundheit verfügt, wissen möchte, ob derzeit Angaben zu psychisch kranken Patienten in der Tabelle enthalten sind. Der Arzt kann eine Abfrage erstellen, die der folgenden ähnelt:

SELECT * FROM physical_health_view
  WHERE 1/IFF(category = 'MentalHealth', 0, 1) = 1;

Diese Abfrage entspricht:

SELECT * FROM patients
  WHERE
    category = 'PhysicalHealth' AND
    1/IFF(category = 'MentalHealth', 0, 1) = 1;

Snowflake verwendet (mindestens) zwei Methoden, um diese Abfrage zu verarbeiten.

  • Methode 1:

    1. Lesen Sie alle Zeilen in der Patiententabelle.

    2. Wenden Sie den Sicherheitsfilter der Ansicht an (d. h. filtern Sie die Zeilen heraus, deren Kategorie nicht PhysicalHealth ist).

    3. Wenden Sie die WHERE-Klausel in der Abfrage an (d. h. filtern Sie basierend auf WHERE 1/IFF(category = 'MentalHealth', 0, 1) = 1).

  • Methode 2 ändert die Reihenfolge der Filter, sodass die Abfrage wie folgt ausgeführt wird:

    1. Lesen Sie alle Zeilen in der Patiententabelle.

    2. Wenden Sie die WHERE-Klausel in der Abfrage an (d. h. filtern Sie basierend auf WHERE 1/IFF(category = 'MentalHealth', 0, 1) = 1).

    3. Wenden Sie den Sicherheitsfilter der Ansicht an (d. h. filtern Sie die Zeilen heraus, deren Kategorie nicht PhysicalHealth ist).

Logisch scheinen diese beiden Sequenzen äquivalent zu sein; sie geben die gleiche Reihe von Zeilen zurück. Abhängig davon, wie selektiv diese beiden Filter sind, kann eine Reihenfolge der Verarbeitung schneller sein. Der Abfrageplaner von Snowflake wählt möglicherweise den Plan, der schneller ausgeführt wird.

Angenommen, das Optimierungsprogramm wählt den zweiten Plan aus, in dem die Klausel WHERE 1/IFF(category = 'MentalHealth', 0, 1) = 1 vor dem Sicherheitsfilter ausgeführt wird. Wenn die Patiententabelle irgendwelche Zeilen enthält, in denen category = 'MentalHealth' enthalten ist, gibt die IFF-Funktion den Wert 0 für diese Zeile zurück, und die Klausel wird tatsächlich zu WHERE 1/0 = 1, sodass die Anweisung einen Fehler wegen Division durch Null verursacht. Der Benutzer mit physical_health_view-Berechtigungen sieht keine Zeilen von Personen mit psychischen Problemen, kann jedoch ableiten, dass mindestens eine Person in der Kategorie „Psychische Gesundheit“ existiert.

Beachten Sie, dass diese Technik nicht immer dazu führt, dass darunterliegende Details sichtbar gemacht werden. Es hängt stark von den Entscheidungen ab, die der Abfrageplaner trifft, und davon, wie die Ansichten (oder UDFs) geschrieben werden. Dieses Beispiel zeigt jedoch, dass ein Benutzer Informationen zu Zeilen ableiten kann, die er nicht direkt anzeigen kann.

Zurück zum Anfang