Zugriffsverlauf¶
Unter diesem Thema werden Konzepte zum Benutzerzugriffsverlauf in Snowflake bereitgestellt.
Unter diesem Thema:
Übersicht¶
Der Zugriffsverlauf in Snowflake bezieht sich darauf, wann die Benutzerabfrage Daten liest und wann die SQL-Anweisung eine Datenschreiboperation wie INSERT, UPDATE und DELETE sowie Variationen des COPY-Befehls vom Quelldatenobjekt zum Zieldatenobjekt ausführt. Der Benutzerzugriffsverlauf kann durch Abfrage der Account Usage-Ansicht ACCESS_HISTORY abgerufen werden. Mithilfe der Datensätze in dieser Ansicht kann die Einhaltung gesetzlicher Bestimmungen einfacher geprüft werden, und sie bieten Einblick in beliebte und häufig abgefragte Tabellen und Spalten, denn es gibt eine direkte Verbindung zwischen dem Benutzer (d. h. Abfrageoperator), der Abfrage, der Tabelle bzw. Ansicht, der Spalte und den Daten.
Jede Zeile in der ACCESS_HISTORY-Ansicht enthält einen einzelnen Datensatz pro SQL-Anweisung. Der Datensatz enthält die folgenden Arten von Informationen:
Die Quellspalten, auf die die Abfrage direkt und indirekt zugreift, wie die zugrunde liegenden Tabellen, aus denen die Daten für die Abfrage stammen.
Die projizierten Spalten, die dem Benutzer im Abfrageergebnis angezeigt werden, wie z. B. die in einer SELECT-Anweisung angegebenen Spalten.
Die Spalten, die zur Bestimmung des Abfrageergebnisses verwendet, aber nicht projiziert werden, wie z. B. Spalten in einer WHERE-Klausel zum Filtern des Ergebnisses.
Beispiel:
CREATE OR REPLACE VIEW v1 (vc1, vc2) AS
SELECT c1 as vc1,
c2 as vc2
FROM t
WHERE t.c3 > 0
;
Die Spalten C1 und C2 sind Quellspalten, auf die die Ansicht direkt zugreift und die in der Spalte
base_objects_accessed
der ACCESS_HISTORY-Ansicht erfasst werden.Die Spalte C3 wird verwendet, um die Zeilen zu filtern, die die Ansicht enthält, die in der Spalte
base_objects_accessed
der ACCESS_HISTORY-Ansicht erfasst wird.Die Spalten VC1 und VC2 sind projizierte Spalten, die dem Benutzer beim Abfragen der Ansicht mit
SELECT * FROM v1;
angezeigt und die in der Spaltedirect_objects_accessed
der ACCESS_HISTORY-Ansicht erfasst werden.
Das gleiche Verhalten gilt für eine Schlüsselspalte einer WHERE-Klausel. Beispiel:
CREATE OR REPLACE VIEW join_v (vc1, vc2, c1) AS
SELECT
bt.c1 AS vc1,
bt.c2 AS vc2,
jt.c1
FROM bt, jt
WHERE bt.c3 = jt.c1;
Zum Erstellen der Ansicht sind zwei verschiedene Tabellen erforderlich:
bt
(Basistabelle) undjt
(Verknüpfungstabelle).Die Spalten C1, C2 und C3 aus der Basistabelle und die Spalte C1 aus der Verknüpfungstabelle werden alle in der Spalte
base_objects_accessed
der ACCESS_HISTORY-Ansicht erfasst.Die Spalten VC1, VC2 und C1 sind projizierte Spalten, die dem Benutzer beim Abfragen der Ansicht mit
SELECT * FROM join_v;
angezeigt und die in der Spaltedirect_objects_accessed
der ACCESS_HISTORY-Ansicht erfasst werden.
Bemerkung
Datensätze in der Account Usage-Ansicht QUERY_HISTORY werden nicht immer in der Ansicht ACCESS_HISTORY erfasst. Die Struktur der SQL-Anweisung bestimmt, ob Snowflake Datensätze in der ACCESS_HISTORY-Ansicht erfasst.
Einzelheiten zu den Lese- und Schreiboperationen, die Snowflake in der ACCESS_HISTORY-Ansicht unterstützt, finden Sie unter Nutzungshinweise.
Verfolgen von Lese- und Schreiboperationen¶
Die ACCESS_HISTORY-Ansicht enthält folgende Spalten:
query_id | query_start_time | user_name | direct_objects_accessed | base_objects_accessed | objects_modified | object_modified_by_ddl | policies_referenced | parent_query_id | root_query_id
Leseoperationen werden über die ersten fünf Spalten verfolgt, während die letzte Spalte objects_modified
die Datenschreibinformationen angibt, die Snowflake-Spalten, -Tabellen und -Stagingbereiche betreffen.
Die Abfrage in Snowflake und die Methode zum Erstellen von Datenbankobjekten bestimmen die Informationen, die Snowflake in den Spalten direct_objects_accessed
, base_objects_accessed
und objects_modified
zurückgibt.
Gleiches gilt, wenn die Abfrage auf ein Objekt verweist, das durch eine Zeilenzugriffsrichtlinie geschützt ist, oder auf eine Spalte, die durch eine Maskierungsrichtlinie geschützt ist, erfasst Snowflake die Richtlinieninformationen in der Spalte policies_referenced
.
In der Spalte object_modified_by_ddl
wird die auf einer Datenbank, einem Schema, einer Tabelle, einer Ansicht oder einer Spalte ausgeführte DDL-Operation erfasst. Zu diesen Operationen gehören auch Anweisungen, die eine Zeilenzugriffsrichtlinie auf einer Tabelle oder Ansicht, eine Maskierungsrichtlinie auf einer Spalte sowie Tag-Aktualisierungen (z. B. Setzen eines Tags, Ändern eines Tag-Werts) auf dem Objekt oder der Spalte angeben.
Die Spalten parent_query_id
und root_query_id
erfassen die Abfrage-IDs, die Folgendem entsprechen:
Abfrage, die eine Lese- oder Schreiboperation auf einem anderen Objekt ausführt.
Abfrage, die eine Lese- oder Schreiboperation auf einem Objekt ausführt, die eine gespeicherte Prozedur aufruft, einschließlich verschachtelter Prozeduraufrufe. Weitere Informationen dazu finden Sie unter Vorgängerabfragen (unter diesem Thema).
Weitere Informationen zu den Spalten finden Sie im Abschnitt Spalten zur ACCESS_HISTORY-Ansicht.
Lesen¶
Betrachten Sie das folgende Szenario, um ein besseres Verständnis der Leseabfrage und der Erfassung dieser Informationen in der ACCESS_HISTORY-Ansicht zu erhalten:
Eine Reihe von Objekten:
base_table
»view_1
»view_2
»view_3
.Eine Leseabfrage auf
view_2
, wie z. B.:select * from view_2;
In diesem Beispiel gibt Snowflake Folgendes zurück:
view_2
in der Spaltedirect_objects_accessed
, weil in der Abfrageview_2
angegeben ist.base_table
in der Spaltebase_objects_accessed
, da dies die ursprüngliche Quelle der Daten inview_2
ist.
Beachten Sie, dass view_1
und view_3
nicht in den Spalten direct_objects_accessed
und base_objects_accessed
enthalten sind, da keine dieser Ansichten in der Abfrage enthalten war und sie nicht das Basisobjekt sind, das als Quelle für die Daten in view_2
dient.
Schreiben¶
Betrachten Sie das folgende Szenario, um ein besseres Verständnis der Schreiboperation und der Erfassung dieser Informationen in der ACCESS_HISTORY-Ansicht zu erhalten:
Eine Datenquelle:
base_table
Erstellen Sie eine Tabelle aus der Datenquelle (d. h. CTAS):
create table table_1 as select * from base_table;
In diesem Beispiel gibt Snowflake Folgendes zurück:
base_table
in den Spaltenbase_objects_accessed
unddirect_objects_accessed
, da auf die Tabelle direkt zugegriffen wurde und sie die Quelle der Daten ist.table_1
in der Spalteobjects_modified
mit den Spalten, in die beim Erstellen der Tabelle geschrieben wurde.
Spaltenherkunft¶
Spaltenherkunft (d. h. der Zugriffsverlauf von Spalten) erweitert die Account Usage-Ansicht ACCESS_HISTORY umd die Angabe, wie die Daten bei einer Schreiboperation von der Quellspalte zur Zielspalte gelangen. Snowflake verfolgt die Daten aus den Quellspalten über alle nachfolgenden Tabellenobjekte, die auf Daten aus den Quellspalten verweisen (z. B. INSERT, MERGE, CTAS), vorausgesetzt, dass Objekte in der Herkunftsabfolge nicht gelöscht werden. Snowflake stellt die Spaltenherkunft bereit, indem die ACCESS_HISTORY-Ansicht um die Spalte objects_modified
erweitert wird.
Weitere Informationen dazu finden Sie unter:
Vorteile (unter diesem Thema)
Beispiel: Spaltenherkunft (unter diesem Thema)
Richtlinienreferenzen zu Maskierungs- und Zeilenzugriffsrichtlinien¶
Die Spalte POLICY_REFERENCED gibt das Objekt an, das eine Zeilenzugriffsrichtlinie für eine Tabelle bzw. eine Maskierungsrichtlinie für eine Spalte hat, einschließlich aller Zwischenobjekte, die entweder durch eine Zeilenzugriffsrichtlinie oder eine Maskierungsrichtlinie geschützt sind. Snowflake erfasst die Richtlinie, die für die Tabelle oder Spalte erzwungen wird.
Betrachten Sie diese Objekte:
t1
» v1
» v2
Wobei:
t1
ist eine Basistabelle.v1
ist eine aus der Basistabelle erstellte Ansicht.v2
ist eine ausv1
erstellte Ansicht.
Wenn der Benutzer v2
abfragt, wird in der Spalte policies_referenced
entweder die Zeilenzugriffsrichtlinie, die v2
schützt, oder jede Maskierungsrichtlinie, die die Spalten in v2
schützt, oder es werden ggf. beide Arten von Richtlinien erfasst. Außerdem werden in dieser Spalte alle Maskierungs- oder Zeilenzugriffsrichtlinien erfasst, die t1
und v1
schützen.
Anhand dieser Datensätze können Datenverwalter nachvollziehen, wie auf ihre richtliniengeschützten Objekte zugegriffen wird.
Die Spalte policies_referenced
bietet weitere Vorteile für die ACCESS_HISTORY-Ansicht:
Identifizieren der richtliniengeschützten Objekte, auf die ein Benutzer in einer bestimmten Abfrage zugreift.
Vereinfachen des Prüfprozesses (Auditing) von Richtlinien.
Durch Abfragen der ACCESS_HISTORY-Ansicht sind keine komplexen Verknüpfungen mit anderen Account Usage-Ansichten (z. B. POLICY_REFERENCES und QUERY_HISTORY) mehr erforderlich, um Informationen zu den geschützten Objekten und den geschützten Spalten zu erhalten, auf die ein Benutzer Zugriff hat.
Unterstützte Operationen¶
Eine vollständige Beschreibung der von der ACCESS_HISTORY-Ansicht unterstützten Lese- und Schreiboperationen finden Sie im Abschnitt „Nutzungshinweise“ unter ACCESS_HISTORY-Ansicht.
Vorteile¶
Der Zugriffsverlauf in Snowflake bietet die folgenden Vorteile in Bezug auf Lese- und Schreiboperationen:
- Datenerkennung:
Erkennen von nicht verwendeten Daten, um zu entscheiden, ob die Daten archiviert oder gelöscht werden sollen.
- Verfolgen der Bewegung sensibler Daten:
Verfolgen Sie Datenbewegungen von einem externen Cloudspeicherort (z. B. Amazon S3-Bucket) zur Snowflake-Zieltabelle und umgekehrt.
Verfolgen Sie interne Datenbewegungen von einer Snowflake-Tabelle zu einer anderen Snowflake-Tabelle.
Nachdem Sie die Bewegung sensibler Daten verfolgt haben, wenden Sie Richtlinien (Maskierung und Zeilenzugriff) an, um die Daten zu schützen, aktualisieren Sie die Zugriffssteuerungseinstellungen, um den Zugriff auf Stagingbereich und Tabelle weiter zu regulieren, und setzen Sie Tags, um sicherzustellen, dass Stagingbereiche, Tabellen und Spalten mit sensiblen Daten für Compliance-Anforderungen nachverfolgt werden können.
- Datenvalidierung:
Die Genauigkeit und Integrität von Berichten, Dashboards und Datenvisualisierungsprodukten wie Diagrammen und Grafiken werden validiert, da die Daten bis zu ihrer ursprünglichen Quelle zurückverfolgt werden können.
Datenverwalter können Benutzer benachrichtigen, bevor eine bestimmte Tabelle oder Ansicht gelöscht oder geändert wird.
- Compliance-Prüfung:
Identifizieren Sie den Snowflake-Benutzer, der eine Schreiboperation auf einer Tabelle oder einem Stagingbereich ausgeführt hat, und wann diese Schreiboperation stattgefunden hat, um Compliance-Anforderungen wie GDPR oder CCPA zu erfüllen.
- Verbesserung der allgemeinen Data Governance:
Die ACCESS_HISTORY-Ansicht bietet einen Gesamtüberblick, auf welche Daten zugegriffen wurde, wann der Datenzugriff stattfand und wie die Daten, auf die zugegriffen wurde, vom Datenquellenobjekt zum Datenzielobjekt verschoben wurden.
Die Spaltenherkunft bietet folgende weitere Vorteile:
- Abgeleitete Objekte schützen:
Datenverwalter können auf Quellspalten mit sensiblen Daten auf einfache Weise Tags setzen, ohne dass nach dem Erstellen abgeleiteter Objekte (z. B. CTAS) zusätzlicher Aufwand erforderlich ist. Anschließend kann der Datenverwalter Tabellen, die sensible Spalten enthalten, mit einer Zeilenzugriffsrichtlinie schützen oder die sensiblen Spalten selbst entweder mit einer Maskierungsrichtlinie oder einer Tag-basierten Maskierungsrichtlinie schützen.
- Kopierhäufigkeit von Spalten mit sensiblen Daten:
Datenschutzbeauftragte können schnell die Objektanzahl (z. B. 1 Tabelle, 2 Ansichten) einer Spalte ermitteln, die sensible Daten enthält. Mit dem Wissen, wie oft eine Spalte mit sensiblen Daten in einem Tabellenobjekt vorkommt, können die Datenschutzbeauftragten nachweisen, wie Standards für die Einhaltung von Vorschriften, wie z. B. der Datenschutz-Grundverordnung (DGVO) in der Europäischen Union, erfüllt werden.
- Ursachenanalyse:
Die Spaltenherkunft bietet einen Mechanismus zur Rückverfolgung von Daten bis zu ihrer Quelle, was dazu beitragen kann, Fehlerpunkte zu identifizieren, die auf eine schlechte Datenqualität zurückzuführen sind, und die Anzahl der zu analysierenden Spalten während der Problembehandlung zu reduzieren.
Abfragen der ACCESS_HISTORY-Ansicht¶
Die folgenden Abschnitte enthalten Beispielabfragen für die ACCESS_HISTORY-Ansicht.
Beachten Sie, dass einige der Beispielabfragen nach der Spalte query_start_time
filtern, um die Abfrageleistung zu erhöhen. Eine weitere Möglichkeit, die Leistung zu erhöhen, ist die Einengung des Zeitbereichs, auf dem die Abfrage ausgeführt wird.
Beispiele: Leseabfragen¶
In den folgenden Unterabschnitten wird beschrieben, wie die ACCESS_HISTORY-Ansicht für Leseoperationen in den folgenden Anwendungsfälle abgefragt werden kann:
Abrufen des Zugriffsverlaufs für einen bestimmten Benutzer.
Vereinfachen der Compliance-Prüfungen für den Zugriff auf sensible Daten in den letzten 30 Tagen auf Basis von
object_id
(z. B. einer Tabellen-ID), um die folgenden Fragen zu beantworten:Wer hat auf die Daten zugegriffen?
Wann wurde auf die Daten zugegriffen?
Auf welche Spalten wurde zugegriffen?
Benutzerzugriffsverlauf zurückgeben¶
Geben Sie den Zugriffsverlauf des Benutzers zurück, sortiert nach Benutzer und Startzeit der Abfrage, beginnend mit dem letzten Zugriff.
SELECT user_name , query_id , query_start_time , direct_objects_accessed , base_objects_accessed FROM access_history ORDER BY 1, 3 desc ;
Compliance-Prüfungen vereinfachen¶
Die folgenden Beispiele helfen, die Einhaltung gesetzlicher Bestimmungen zu vereinfachen:
Fügen Sie den
object_id
-Wert hinzu, um festzustellen, wer in den letzten 30 Tagen auf eine sensible Tabelle zugegriffen hat:SELECT distinct user_name FROM access_history , lateral flatten(base_objects_accessed) f1 WHERE f1.value:"objectId"::int=<fill_in_object_id> AND f1.value:"objectDomain"::string='Table' AND query_start_time >= dateadd('day', -30, current_timestamp()) ;
Bestimmen Sie anhand des
object_id
-Wertes von32998411400350
, wann der Zugriff in den letzten 30 Tagen erfolgte:SELECT query_id , query_start_time FROM access_history , lateral flatten(base_objects_accessed) f1 WHERE f1.value:"objectId"::int=32998411400350 AND f1.value:"objectDomain"::string='Table' AND query_start_time >= dateadd('day', -30, current_timestamp()) ;
Bestimmen Sie anhand des
object_id
-Wertes von32998411400350
, auf welche Spalten in den letzten 30 Tagen zugegriffen wurde:SELECT distinct f4.value AS column_name FROM access_history , lateral flatten(base_objects_accessed) f1 , lateral flatten(f1.value) f2 , lateral flatten(f2.value) f3 , lateral flatten(f3.value) f4 WHERE f1.value:"objectId"::int=32998411400350 AND f1.value:"objectDomain"::string='Table' AND f4.key='columnName' ;
Beispiele: Schreiboperationen¶
In den folgenden Unterabschnitten wird beschrieben, wie die ACCESS_HISTORY-Ansicht für Schreiboperationen in den folgenden Anwendungsfälle abgefragt werden kann:
Laden von Daten aus einem Stagingbereich in eine Tabelle
Entladen von Daten aus einer Tabelle in einen Stagingbereich
Verwenden des PUT-Befehls zum Hochladen einer lokale Datei in einen Stagingbereich
Verwenden des GET-Befehls zum Abrufen von Datendateien aus einem Stagingbereich in ein lokales Verzeichnis
Verfolgen der Bewegung sensibler Stagingbereichsdaten
Daten aus einem Stagingbereich in eine Tabelle laden¶
Laden Sie eine Menge von Werten aus einer Datendatei in einen externen Cloudspeicher in Spalten einer Zieltabelle.
copy into table1(col1, col2) from (select t.$1, t.$2 from @mystage1/data1.csv.gz);
In den Spalten direct_objects_accessed
und base_objects_accessed
wird angegeben, dass auf einen externen benannten Stagingbereich zugegriffen wurde:
{ "objectDomain": STAGE "objectName": "mystage1", "objectId": 1, "stageKind": "External Named" }
In der Spalte objects_modified
wird angegeben, dass Daten in zwei Spalten der Tabelle geschrieben wurden:
{ "columns": [ { "columnName": "col1", "columnId": 1 }, { "columnName": "col2", "columnId": 2 } ], "objectId": 1, "objectName": "TEST_DB.TEST_SCHEMA.TABLE1", "objectDomain": TABLE }
Daten aus einer Tabelle in einen Stagingbereich entladen¶
Entladen Sie eine Menge von Werten aus einer Snowflake-Tabelle in den Cloudspeicher.
copy into @mystage1/data1.csv from table1;
In den Spalten direct_objects_accessed
und base_objects_accessed
werden die Tabellenspalten angegeben, auf die zugegriffen wurde:
{ "objectDomain": TABLE "objectName": "TEST_DB.TEST_SCHEMA.TABLE1", "objectId": 123, "columns": [ { "columnName": "col1", "columnId": 1 }, { "columnName": "col2", "columnId": 2 } ] }
In der Spalte objects_modified
wird der Stagingbereich angegeben, in den die abgerufenen Daten geschrieben wurden:
{ "objectId": 1, "objectName": "mystage1", "objectDomain": STAGE, "stageKind": "External Named" }
PUT-Befehl zum Hochladen einer lokalen Datei in einen Stagingbereich verwenden¶
Kopieren Sie eine Datendatei in einen internen (d. h. Snowflake) Stagingbereich.
put file:///tmp/data/mydata.csv @my_int_stage;
In den Spalten direct_objects_accessed
und base_objects_accessed
wird der lokale Pfad zu der Datei angegeben, auf die zugegriffen wurde:
{ "location": "file:///tmp/data/mydata.csv" }
In der Spalte objects_modified
wird der Stagingbereich angegeben, in den die abgerufenen Daten geschrieben wurden:
{ "objectId": 1, "objectName": "my_int_stage", "objectDomain": STAGE, "stageKind": "Internal Named" }
GET-Befehl zum Abrufen von Datendateien aus einem Stagingbereich in ein lokales Verzeichnis verwenden¶
Rufen Sie eine Datendatei aus einem internen Stagingbereich in ein Verzeichnis auf dem lokalen Rechner ab.
get @%mytable file:///tmp/data/;
In den Spalten direct_objects_accessed
und base_objects_accessed
werden der Stagingbereich und das lokale Verzeichnis angegeben, auf die zugegriffen wurde:
{ "objectDomain": Stage "objectName": "mytable", "objectId": 1, "stageKind": "Table" }
In der Spalte objects_modified
wird das Verzeichnis angegeben, in das die abgerufenen Daten geschrieben wurden:
{ "location": "file:///tmp/data/" }
Bewegung sensibler Stagingbereichsdaten verfolgen¶
Verfolgen Sie sensible Stagingbereichsdaten, während diese eine Serie von Abfragen in chronologischer Reihenfolge durchlaufen.
Führen Sie die folgenden Abfragen aus. Beachten Sie, dass fünf der Anweisungen auf Stagingbereiche zugreifen. Wenn Sie also die ACCESS_HISTORY-Ansicht für den Stagingbereichszugriff abfragen, sollte das Resultset fünf Zeilen enthalten.
use test_db.test_schema; create or replace table T1(content variant); insert into T1(content) select parse_json('{"name": "A", "id":1}'); -- T1 -> T6 insert into T6 select * from T1; -- S1 -> T1 copy into T1 from @S1; -- T1 -> T2 create table T2 as select content:"name" as name, content:"id" as id from T1; -- T1 -> S2 copy into @S2 from T1; -- S1 -> T3 create or replace table T3(customer_info variant); copy into T3 from @S1; -- T1 -> T4 create or replace table T4(name string, id string, address string); insert into T4(name, id) select content:"name", content:"id" from T1; -- T6 -> T7 create table T7 as select * from T6;Wobei:
T1
,T2
…T7
geben die Namen der Tabellen an.
S1
undS2
geben die Namen der Stagingbereiche an.
Führen Sie eine Abfrage des Zugriffsverlaufs aus, um den Zugriff auf Stagingbereich S1
zu ermitteln.
Die Daten der Spalten
direct_objects_accessed
,base_objects_accessed
undobjects_modified
sind in der folgenden Tabelle aufgeführt.
direct_objects_accessed
base_objects_accessed
objects_modified
[ { "columns": [ { "columnId": 68610, "columnName": "CONTENT" } ], "objectDomain": "Table", "objectId": 66564, "objectName": "TEST_DB.TEST_SCHEMA.T1" } ] [ { "columns": [ { "columnId": 68610, "columnName": "CONTENT" } ], "objectDomain": "Table", "objectId": 66564, "objectName": "TEST_DB.TEST_SCHEMA.T1" } ] [ { "columns": [ { "columnId": 68611, "columnName": "CONTENT" } ], "objectDomain": "Table", "objectId": 66566, "objectName": "TEST_DB.TEST_SCHEMA.T6" } ] [ { "objectDomain": "Stage", "objectId": 117, "objectName": "TEST_DB.TEST_SCHEMA.S1", "stageKind": "External Named" } ] [ { "objectDomain": "Stage", "objectId": 117, "objectName": "TEST_DB.TEST_SCHEMA.S1", "stageKind": "External Named" } ] [ { "columns": [ { "columnId": 68610, "columnName": "CONTENT" } ], "objectDomain": "Table", "objectId": 66564, "objectName": "TEST_DB.TEST_SCHEMA.T1" } ] [ { "columns": [ { "columnId": 68610, "columnName": "CONTENT" } ], "objectDomain": "Table", "objectId": 66564, "objectName": "TEST_DB.TEST_SCHEMA.T1" } ] [ { "columns": [ { "columnId": 68610, "columnName": "CONTENT" } ], "objectDomain": "Table", "objectId": 66564, "objectName": "TEST_DB.TEST_SCHEMA.T1" } ] [ { "columns": [ { "columnId": 68613, "columnName": "ID" }, { "columnId": 68612, "columnName": "NAME" } ], "objectDomain": "Table", "objectId": 66568, "objectName": "TEST_DB.TEST_SCHEMA.T2" } ] [ { "columns": [ { "columnId": 68610, "columnName": "CONTENT" } ], "objectDomain": "Table", "objectId": 66564, "objectName": "TEST_DB.TEST_SCHEMA.T1" } ] [ { "columns": [ { "columnId": 68610, "columnName": "CONTENT" } ], "objectDomain": "Table", "objectId": 66564, "objectName": "TEST_DB.TEST_SCHEMA.T1" } ] [ { "objectDomain": "Stage", "objectId": 118, "objectName": "TEST_DB.TEST_SCHEMA.S2", "stageKind": "External Named" } ] [ { "objectDomain": "Stage", "objectId": 117, "objectName": "TEST_DB.TEST_SCHEMA.S1", "stageKind": "External Named" } ] [ { "objectDomain": "Stage", "objectId": 117, "objectName": "TEST_DB.TEST_SCHEMA.S1", "stageKind": "External Named" } ] [ { "columns": [ { "columnId": 68614, "columnName": "CUSTOMER_INFO" } ], "objectDomain": "Table", "objectId": 66570, "objectName": "TEST_DB.TEST_SCHEMA.T3" } ] [ { "columns": [ { "columnId": 68610, "columnName": "CONTENT" } ], "objectDomain": "Table", "objectId": 66564, "objectName": "TEST_DB.TEST_SCHEMA.T1" } ] [ { "columns": [ { "columnId": 68610, "columnName": "CONTENT" } ], "objectDomain": "Table", "objectId": 66564, "objectName": "TEST_DB.TEST_SCHEMA.T1" } ] [ { "columns": [ { "columnId": 68615, "columnName": "NAME" }, { "columnId": 68616, "columnName": "ID" } ], "objectDomain": "Table", "objectId": 66572, "objectName": "TEST_DB.TEST_SCHEMA.T4" } ] [ { "columns": [ { "columnId": 68611, "columnName": "CONTENT" } ], "objectDomain": "Table", "objectId": 66566, "objectName": "TEST_DB.TEST_SCHEMA.T6" } ] [ { "columns": [ { "columnId": 68611, "columnName": "CONTENT" } ], "objectDomain": "Table", "objectId": 66566, "objectName": "TEST_DB.TEST_SCHEMA.T6" } ] [ { "columns": [ { "columnId": 68618, "columnName": "CONTENT" } ], "objectDomain": "Table", "objectId": 66574, "objectName": "TEST_DB.TEST_SCHEMA.T7" } ]Beachten Sie bei diesem Abfragebeispiel Folgendes:
Verwendet einen rekursiven allgemeinen Tabellenausdruck.
Verwendet ein JOIN-Konstrukt anstelle einer USING-Klausel.
with access_history_flatten as ( select r.value:"objectId" as source_id, r.value:"objectName" as source_name, r.value:"objectDomain" as source_domain, w.value:"objectId" as target_id, w.value:"objectName" as target_name, w.value:"objectDomain" as target_domain, c.value:"columnName" as target_column, t.query_start_time as query_start_time from (select * from TEST_DB.ACCOUNT_USAGE.ACCESS_HISTORY) t, lateral flatten(input => t.BASE_OBJECTS_ACCESSED) r, lateral flatten(input => t.OBJECTS_MODIFIED) w, lateral flatten(input => w.value:"columns", outer => true) c ), sensitive_data_movements(path, target_id, target_name, target_domain, target_column, query_start_time) as -- Common Table Expression ( -- Anchor Clause: Get the objects that access S1 directly select f.source_name || '-->' || f.target_name as path, f.target_id, f.target_name, f.target_domain, f.target_column, f.query_start_time from access_history_flatten f where f.source_domain = 'Stage' and f.source_name = 'TEST_DB.TEST_SCHEMA.S1' and f.query_start_time >= dateadd(day, -30, date_trunc(day, current_date)) union all -- Recursive Clause: Recursively get all the objects that access S1 indirectly select sensitive_data_movements.path || '-->' || f.target_name as path, f.target_id, f.target_name, f.target_domain, f.target_column, f.query_start_time from access_history_flatten f join sensitive_data_movements on f.source_id = sensitive_data_movements.target_id and f.source_domain = sensitive_data_movements.target_domain and f.query_start_time >= sensitive_data_movements.query_start_time ) select path, target_name, target_id, target_domain, array_agg(distinct target_column) as target_columns from sensitive_data_movements group by path, target_id, target_name, target_domain;Die Abfrage liefert das folgende Resultset in Bezug auf die Datenbewegung in Stagingbereich
S1
:
PATH
TARGET_NAME
TARGET_ID
TARGET_DOMAIN
TARGET_COLUMNS
TEST_DB.TEST_SCHEMA.S1–>TEST_DB.TEST_SCHEMA.T1
TEST_DB.TEST_SCHEMA.T1
66564
Tabelle
[„CONTENT“]
TEST_DB.TEST_SCHEMA.S1–>TEST_DB.TEST_SCHEMA.T1–>TEST_DB.TEST_SCHEMA.S2
TEST_DB.TEST_SCHEMA.S2
118
Stagingbereich
[]
TEST_DB.TEST_SCHEMA.S1–>TEST_DB.TEST_SCHEMA.T1–>TEST_DB.TEST_SCHEMA.T2
TEST_DB.TEST_SCHEMA.T2
66568
Tabelle
[„NAME“,“ID“]
TEST_DB.TEST_SCHEMA.S1–>TEST_DB.TEST_SCHEMA.T1–>TEST_DB.TEST_SCHEMA.T4
TEST_DB.TEST_SCHEMA.T4
66572
Tabelle
[„ID“,“NAME“]
TEST_DB.TEST_SCHEMA.S1–>TEST_DB.TEST_SCHEMA.T3
TEST_DB.TEST_SCHEMA.T3
66570
Tabelle
[„CUSTOMER_INFO“]
Beispiel: Spaltenherkunft¶
Im folgenden Beispiel wird die ACCESS_HISTORY-Ansicht abgefragt, und die Funktion FLATTEN wird verwendet, um die Spalte objects_modified
zu vereinfachen.
Führen Sie als repräsentatives Beispiel die folgende SQL-Abfrage in Ihrem Snowflake-Konto aus, um die folgende Tabelle zu erstellen, in der die nummerierten Kommentare Folgendes angeben:
// 1
: Ermittelt die Zuordnung zwischen dem FelddirectSources
und der Zielspalte.// 2
: Ermittelt die Zuordnung zwischen dem FeldbaseSources
und der Zielspalte.
// 1
select
directSources.value: "objectId" as source_object_id,
directSources.value: "objectName" as source_object_name,
directSources.value: "columnName" as source_column_name,
'DIRECT' as source_column_type,
om.value: "objectName" as target_object_name,
columns_modified.value: "columnName" as target_column_name
from
(
select
*
from
snowflake.account_usage.access_history
) t,
lateral flatten(input => t.OBJECTS_MODIFIED) om,
lateral flatten(input => om.value: "columns", outer => true) columns_modified,
lateral flatten(
input => columns_modified.value: "directSources",
outer => true
) directSources
union
// 2
select
baseSources.value: "objectId" as source_object_id,
baseSources.value: "objectName" as source_object_name,
baseSources.value: "columnName" as source_column_name,
'BASE' as source_column_type,
om.value: "objectName" as target_object_name,
columns_modified.value: "columnName" as target_column_name
from
(
select
*
from
snowflake.account_usage.access_history
) t,
lateral flatten(input => t.OBJECTS_MODIFIED) om,
lateral flatten(input => om.value: "columns", outer => true) columns_modified,
lateral flatten(
input => columns_modified.value: "baseSources",
outer => true
) baseSources
;
Rückgabewerte:
SOURCE_OBJECT_ID
SOURCE_OBJECT_NAME
SOURCE_COLUMN_NAME
SOURCE_COLUMN_TYPE
TARGET_OBJECT_NAME
TARGET_COLUMN_NAME
1
D.S.T0
NAME
BASE
D.S.T1
NAME
2
D.S.V1
NAME
DIRECT
D.S.T1
NAME
Beispiel: Richtlinienreferenzen von Zeilenzugriffsrichtlinien verfolgen¶
Gibt eine Zeile für jede Instanz zurück, wenn eine Zeilenzugriffsrichtlinie für eine Tabelle, Ansicht oder materialisierte Ansicht ohne Duplikate festgelegt ist:
use role accountadmin; select distinct obj_policy.value:"policyName"::VARCHAR as policy_name from snowflake.account_usage.access_history as ah , lateral flatten(ah.policies_referenced) as obj , lateral flatten(obj.value:"policies") as obj_policy ;
Beispiel: Richtlinienreferenzen von Maskierungsrichtlinien verfolgen¶
Gibt eine Zeile für jede Instanz zurück, wenn eine Maskierungsrichtlinie eine Spalte ohne Duplikate schützt. Beachten Sie, dass eine zusätzliche Vereinfachung (Flattening) erforderlich ist, da die policies_referenced
-Spalte die Maskierungsrichtlinie einer Spalte eine Ebene tiefer als die Zeilenzugriffsrichtlinie einer Tabelle angibt:
use role accountadmin; select distinct policies.value:"policyName"::VARCHAR as policy_name from snowflake.account_usage.access_history as ah , lateral flatten(ah.policies_referenced) as obj , lateral flatten(obj.value:"columns") as columns , lateral flatten(columns.value:"policies") as policies ;
Beispiel: Erzwungene Richtlinie in einer Abfrage verfolgen¶
Gibt den Zeitpunkt zurück, zu dem die Richtlinie aktualisiert wurde (POLICY_CHANGED_TIME) und die Richtlinienbedingungen (POLICY_BODY) für eine bestimmte Abfrage in einem gegebenen Zeitrahmen.
Bevor Sie diese Abfrage verwenden, aktualisieren Sie die Eingabewerte der WHERE-Klausel:
where query_start_time > '2023-07-07' and
query_start_time < '2023-07-08' and
query_id = '01ad7987-0606-6e2c-0001-dd20f12a9777')
Wobei:
query_start_time > '2023-07-07'
Gibt den Anfangszeitstempel an.
query_start_time < '2023-07-08'
Gibt den Endzeitstempel an.
query_id = '01ad7987-0606-6e2c-0001-dd20f12a9777'
Gibt die Abfrage-ID in der Account Usage-Ansicht ACCESS_HISTORY an.
Führen Sie die Abfrage aus:
SELECT *
from(
select j1.*,j2.QUERY_START_TIME as POLICY_CHANGED_TIME, POLICY_BODY
from
(
select distinct t1.*,
t4.value:"policyId"::number as PID
from (select *
from SNOWFLAKE.ACCOUNT_USAGE.ACCESS_HISTORY
where query_start_time > '2023-07-07' and
query_start_time < '2023-07-08' and
query_id = '01ad7987-0606-6e2c-0001-dd20f12a9777') as t1, //
lateral flatten (input => t1.POLICIES_REFERENCED,OUTER => TRUE) t2,
lateral flatten (input => t2.value:"columns", OUTER => TRUE) t3,
lateral flatten (input => t3.value:"policies",OUTER => TRUE) t4
) as j1
left join
(
select OBJECT_MODIFIED_BY_DDL:"objectId"::number as PID,
QUERY_START_TIME,
OBJECT_MODIFIED_BY_DDL:"properties"."policyBody"."value" as POLICY_BODY
from SNOWFLAKE.ACCOUNT_USAGE.ACCESS_HISTORY
where OBJECT_MODIFIED_BY_DDL is not null and
(OBJECT_MODIFIED_BY_DDL:"objectDomain" ilike '%masking%' or OBJECT_MODIFIED_BY_DDL:"objectDomain" ilike '%row%')
) as j2
On j1.POLICIES_REFERENCED is not null and j1.pid = j2.pid and j1.QUERY_START_TIME>j2.QUERY_START_TIME) as j3
QUALIFY ROW_NUMBER() OVER (PARTITION BY query_id,pid ORDER BY policy_changed_time DESC) = 1;
Beispiele: UDFs¶
Die folgenden UDF-Beispiele zeigen, wie die Account Usage-Ansicht ACCESS_HISTORY Daten erfasst:
Aufrufen einer UDF namens
get_product
.Einfügen des Produkts aus dem Aufruf der Funktion
get_product
in eine Tabelle namensmydb.tables.t1
.Freigeben von UDFs.
Aufrufen einer UDF¶
Angenommen, die folgende SQL-UDF berechnet das Produkt zweier Zahlen und speichert das Ergebnis im Schema namens mydb.udfs
:
CREATE FUNCTION MYDB.UDFS.GET_PRODUCT(num1 number, num2 number) RETURNS number AS $$ NUM1 * NUM2 $$ ;
Das direkte Aufrufen von get_product
führt zum Erfassen der UDF-Details in der Spalte direct_objects_accessed
:
[ { "objectDomain": "FUNCTION", "objectName": "MYDB.UDFS.GET_PRODUCT", "objectId": "2", "argumentSignature": "(NUM1 NUMBER, NUM2 NUMBER)", "dataType": "NUMBER(38,0)" } ]
Dieses Beispiel ist analog zum Aufrufen einer gespeicherten Prozedur (unter diesem Thema).
UDF mit INSERT DML¶
Betrachten Sie die folgende INSERT-Anweisung, mit der die Spalten 1 und 2 in der Tabelle mydb.tables.t1
aktualisiert werden:
insert into t1(product) select get_product(c1, c2) from mydb.tables.t1;
Die ACCESS_HISTORY-Ansicht erfasst die get_product
-Funktion in folgenden Spalten:
Spalte
direct_objects_accessed
, da die Funktion in der SQL-Anweisung explizit genannt wirdSpalte
objects_modified
im ArraydirectSources
, da die Funktion die Quelle für die Werte ist, die in die Spalten eingefügt werden.
Außerdem wird auch Tabelle t1
in denselben Spalten erfasst:
direct_objects_accessed
objects_modified
[ { "objectDomain": "FUNCTION", "objectName": "MYDB.UDFS.GET_PRODUCT", "objectId": "2", "argumentSignature": "(NUM1 NUMBER, NUM2 NUMBER)", "dataType": "NUMBER(38,0)" }, { "objectDomain": "TABLE", "objectName": "MYDB.TABLES.T1", "objectId": 1, "columns": [ { "columnName": "c1", "columnId": 1 }, { "columnName": "c2", "columnId": 2 } ] } ] [ { "objectDomain": "TABLE", "objectName": "MYDB.TABLES.T1", "objectId": 2, "columns": [ { "columnId": "product", "columnName": "201", "directSourceColumns": [ { "objectDomain": "Table", "objectName": "MYDB.TABLES.T1", "objectId": "1", "columnName": "c1" }, { "objectDomain": "Table", "objectName": "MYDB.TABLES.T1", "objectId": "1", "columnName": "c2" }, { "objectDomain": "FUNCTION", "objectName": "MYDB.UDFS.GET_PRODUCT", "objectId": "2", "argumentSignature": "(NUM1 NUMBER, NUM2 NUMBER)", "dataType": "NUMBER(38,0)" } ], "baseSourceColumns":[] } ] } ]
Beispiele: Objekte verfolgen, die durch eine DDL-Operation geändert wurden¶
Tag mit Schlüssel ALLOWED_VALUES erstellen¶
So erstellen Sie das Tag:
create tag governance.tags.pii allowed_values 'sensitive','public';
Spaltenwert:
{ "objectDomain": "TAG", "objectName": "governance.tags.pii", "objectId": "1", "operationType": "CREATE", "properties": { "allowedValues": { "sensitive": { "subOperationType": "ADD" }, "public": { "subOperationType": "ADD" } } } }
Bemerkung
Wenn Sie beim Erstellen des Tags keine zulässigen Werte angeben, ist das Feld properties
ein leeres Array (d. h. {}
).
Tabelle mit einem Tag und Maskierungsrichtlinie erstellen¶
So erstellen Sie die Tabelle mit einer Maskierungsrichtlinie auf der Spalte, einem Tag auf der Spalte und einem Tag auf der Tabelle:
create or replace table hr.data.user_info( email string with masking policy governance.policies.email_mask with tag (governance.tags.pii = 'sensitive') ) with tag (governance.tags.pii = 'sensitive');
Spaltenwert:
{ "objectDomain": "TABLE", "objectName": "hr.data.user_info", "objectId": "1", "operationType": "CREATE", "properties": { "tags": { "governance.tags.pii": { "subOperationType": "ADD", "objectId": { "value": "1" }, "tagValue": { "value": "sensitive" } } }, "columns": { "email": { objectId: { "value": 1 }, "subOperationType": "ADD", "tags": { "governance.tags.pii": { "subOperationType": "ADD", "objectId": { "value": "1" }, "tagValue": { "value": "sensitive" } } }, "maskingPolicies": { "governance.policies.email_mask": { "subOperationType": "ADD", "objectId": { "value": 2 } } } } } } }
Maskierungsrichtlinie auf ein Tag setzen¶
So legen Sie eine Maskierungsrichtlinie auf dem Tag fest (d. h. Tag-basiertes Maskieren):
alter tag governance.tags.pii set masking policy governance.policies.email_mask;
Spaltenwert:
{ "objectDomain": "TAG", "objectName": "governance.tags.pii", "objectId": "1", "operationType": "ALTER", "properties": { "maskingPolicies": { "governance.policies.email_mask": { "subOperationType": "ADD", "objectId": { "value": 2 } } } } }
Tabelle austauschen¶
So tauschen Sie die Tabelle mit dem Namen t2
gegen die Tabelle mit dem Namen t3
aus:
alter table governance.tables.t2 swap with governance.tables.t3;
Beachten Sie die beiden unterschiedlichen Datensätze in der Ansicht.
Datensatz 1:
{ "objectDomain": "Table", "objectId": 0, "objectName": "GOVERNANCE.TABLES.T2", "operationType": "ALTER", "properties": { "swapTargetDomain": { "value": "Table" }, "swapTargetId": { "value": 0 }, "swapTargetName": { "value": "GOVERNANCE.TABLES.T3" } } }
Datensatz 2:
{ "objectDomain": "Table", "objectId": 0, "objectName": "GOVERNANCE.TABLES.T3", "operationType": "ALTER", "properties": { "swapTargetDomain": { "value": "Table" }, "swapTargetId": { "value": 0 }, "swapTargetName": { "value": "GOVERNANCE.TABLES.T2" } } }
Maskierungsrichtlinie löschen¶
So löschen Sie die Maskierungsrichtlinie:
drop masking policy governance.policies.email_mask;
Spaltenwert:
{ "objectDomain" : "MASKING_POLICY", "objectName": "governance.policies.email_mask", "objectId" : "1", "operationType": "DROP", "properties" : {} }Bemerkung
Der Spaltenwert ist repräsentativ und gilt für eine DROP-Operation auf einem Tag und einer Zeilenzugriffsrichtlinie.
Das Feld
properties
ist ein leeres Array. Es enthält keine Informationen zu der Richtlinie vor der DROP-Operation.
Tag-Referenzen auf einer Spalte verfolgen¶
Fragen Sie die Spalte object_modified_by_ddl
ab, um zu überwachen, wie ein Tag auf eine Spalte gesetzt ist.
Als Administrator der Tabelle können Sie ein Tag auf eine Spalte setzen, das Tag wieder entfernen und das Tag mit einem anderen Zeichenfolgenwert aktualisieren:
alter table hr.tables.empl_info alter column email set tag governance.tags.test_tag = 'test'; alter table hr.tables.empl_info alter column email unset tag governance.tags.test_tag; alter table hr.tables.empl_info alter column email set tag governance.tags.data_category = 'sensitive';
Ändern Sie als Data Engineer den Tag-Wert:
alter table hr.tables.empl_info alter column email set tag governance.tags.data_category = 'public';
Fragen Sie die ACCESS_HISTORY-Ansicht ab, um die Änderungen zu überwachen:
select query_start_time, user_name, object_modified_by_ddl:"objectName"::string as table_name, 'EMAIL' as column_name, tag_history.value:"subOperationType"::string as operation, tag_history.key as tag_name, nvl((tag_history.value:"tagValue"."value")::string, '') as value from TEST_DB.ACCOUNT_USAGE.access_history ah, lateral flatten(input => ah.OBJECT_MODIFIED_BY_DDL:"properties"."columns"."EMAIL"."tags") tag_history where true and object_modified_by_ddl:"objectDomain" = 'Table' and object_modified_by_ddl:"objectName" = 'TEST_DB.TEST_SH.T' order by query_start_time asc;
Rückgabewerte:
+-----------------------------------+---------------+---------------------+-------------+-----------+-------------------------------+-----------+ | QUERY_START_TIME | USER_NAME | TABLE_NAME | COLUMN_NAME | OPERATION | TAG_NAME | VALUE | +-----------------------------------+---------------+---------------------+-------------+-----------+-------------------------------+-----------+ | Mon, Feb. 14, 2023 12:01:01 -0600 | TABLE_ADMIN | HR.TABLES.EMPL_INFO | EMAIL | ADD | GOVERNANCE.TAGS.TEST_TAG | test | | Mon, Feb. 14, 2023 12:02:01 -0600 | TABLE_ADMIN | HR.TABLES.EMPL_INFO | EMAIL | DROP | GOVERNANCE.TAGS.TEST_TAG | | | Mon, Feb. 14, 2023 12:03:01 -0600 | TABLE_ADMIN | HR.TABLES.EMPL_INFO | EMAIL | ADD | GOVERNANCE.TAGS.DATA_CATEGORY | sensitive | | Mon, Feb. 14, 2023 12:04:01 -0600 | DATA_ENGINEER | HR.TABLES.EMPL_INFO | EMAIL | ADD | GOVERNANCE.TAGS.DATA_CATEGORY | public | +-----------------------------------+---------------+---------------------+-------------+-----------+-------------------------------+-----------+
Beispiel: Gespeicherte Prozedur aufrufen¶
Angenommen die folgende gespeicherte Prozedur ist im Schema namens mydb.procedures
gespeichert:
create or replace procedure get_id_value(name string) returns string not null language javascript as $$ var my_sql_command = "select id from A where name = '" + NAME + "'"; var statement = snowflake.createStatement( {sqlText: my_sql_command} ); var result = statement.execute(); result.next(); return result.getColumnValue(1); $$ ;
Der direkte Aufruf von my_procedure
führt dazu, dass die Details der Prozedur sowohl in der Spalte direct_objects_accessed
als auch in der Spalte base_objects_accessed
wie folgt erfasst werden:
[ { "objectDomain": "PROCEDURE", "objectName": "MYDB.PROCEDURES.GET_ID_VALUE", "argumentSignature": "(NAME STRING)", "dataType": "STRING" } ]
Dieses Beispiel ist analog zum Aufrufen einer UDF (unter diesem Thema).
Beispiel: Vorgängerabfragen mit gespeicherten Prozeduren¶
Sie können die Spalten parent_query_id
und root_query_id
verwenden, um zu verstehen, wie Aufrufe gespeicherter Prozeduren zueinander in Beziehung stehen.
Angenommen, Sie haben drei verschiedene Anweisungen für gespeicherte Prozeduren und führen diese in folgender Reihenfolge aus:
CREATE OR REPLACE PROCEDURE myproc_child() RETURNS INTEGER LANGUAGE SQL AS $$ BEGIN SELECT * FROM mydb.mysch.mytable; RETURN 1; END $$; CREATE OR REPLACE PROCEDURE myproc_parent() RETURNS INTEGER LANGUAGE SQL AS $$ BEGIN CALL myproc_child(); RETURN 1; END $$; CALL myproc_parent();
Bei einer Abfrage auf der Ansicht ACCESS_HISTORY werden die Informationen wie folgt erfasst:
SELECT query_id, parent_query_id, root_query_id, direct_objects_accessed FROM SNOWFLAKE.ACCOUNT_USAGE.ACCESS_HISTORY;+----------+-----------------+---------------+-----------------------------------+ | QUERY_ID | PARENT_QUERY_ID | ROOT_QUERY_ID | DIRECT_OBJECTS_ACCESSED | +----------+-----------------+---------------+-----------------------------------+ | 1 | NULL | NULL | [{"objectName": "myproc_parent"}] | | 2 | 1 | 1 | [{"objectName": "myproc_child"}] | | 3 | 2 | 1 | [{"objectName": "mytable"}] | +----------+-----------------+---------------+-----------------------------------+
Die erste Zeile entspricht dem Aufruf der zweiten Prozedur namens
myproc_parent
, wie in der Spaltedirect_objects_accessed
gezeigt.Die Spalten
parent_query_id
undroot_query_id
geben NULL zurück, da Sie diese gespeicherte Prozedur direkt aufgerufen haben.Die zweite Zeile entspricht der Abfrage, die die erste Prozedur namens
myproc_child
aufruft, wie in der Spaltedirect_objects_accessed column
angegeben.Die Spalten
parent_query_id
undroot_query_id
geben dieselbe Abfrage-ID zurück, da die Abfrage, diemyproc_child
aufruft, von der Abfrage initiiert wurde, diemyproc_parent
aufruft, die Sie direkt aufgerufen haben.Die dritte Zeile entspricht der Abfrage, die in der Prozedur
myproc_child
auf die Tabellemytable
zugreift, wie in der Spaltedirect_objects_accessed
angegeben.Die Spalte
parent_query_id
gibt die Abfrage-ID der Abfrage zurück, die aufmytable
zugegriffen hat, was einem Aufruf vonmyproc_child
entspricht. Diese gespeicherte Prozedur wurde durch die Abfrage gestartet, diemyproc_parent
aufruft. Sie wird in der Spalteroot_query_id
angezeigt.