Snowpark Container Services: SQL-Ausführung

Ihr Anwendungscontainer kann sich mit Snowflake verbinden und SQL ausführen. Unter diesem Thema wird beschrieben, wie der Containercode die erforderlichen Informationen für die Verbindung zu Snowflake erhält, einschließlich Authentifizierungsdaten, Datenbank- und Schemakontext des Service und das für die Ausführung von SQL-Anweisungen verwendete Warehouse.

Optionen für die Konfiguration der Anmeldeinformationen

Snowflake empfiehlt, dass Anwendungscontainer bei der Ausführung von SQL die von Snowflake bereitgestellten Anmeldeinformationen verwenden, um sich bei Snowflake zu authentifizieren. Obwohl es möglich ist, andere Anmeldeinformationen zu verwenden, indem Sie eine Verbindung über eine Integration für den externen Zugriff (EAI) herstellen, behandelt die Verbindung über eine EAI den Service so, als würde er außerhalb von Snowflake ausgeführt und stellte eine Verbindung zu Snowflake über das Internet her.

Sie haben drei Optionen, um von einem Servicecontainer aus eine Verbindung zu Snowflake herzustellen:

  • Verwenden Sie die von Snowflake bereitgestellten Anmeldeinformationen für den Service: Snowflake liefert jedem Service Anmeldeinformationen, die als Serviceanmeldeinformationen bezeichnet werden. Ein Service verwendet diese Anmeldeinformationen, um sich als Servicebenutzer mit Snowflake zu verbinden.

  • Verwenden Sie von Snowflake bereitgestellte Aufrufer-Anmeldeinformationen (Aufruferrechte): Wenn Sie Ihren Service mit Aufruferrechten konfigurieren, stellt Snowflake auch Anmeldeinformationen bereit, damit der Service sich als aufrufender Benutzer mit Snowflake verbinden kann.

  • Andere Anmeldeinformationen verwenden: In diesem Fall verwenden Sie eine Integration für den externen Zugriff (EAI), die es Ihrem Service ermöglicht, unter Verwendung gültiger Authentifizierungsdaten eine Verbindung zum Internetendpunkt von Snowflake herzustellen. Für diese Option ist ein Administrator erforderlich, um die EAI zu erstellen und dann die USAGE-Berechtigung für die Integration in die Rolle des Serviceeigentümers zu gewähren.

    Bemerkung

    Die Verwendung von Integrationen für den externen Zugriff auf Snowflake kann bedeuten, dass potenziell sensible Informationen über das Internet gesendet werden.

Beispiele für Code, der verschiedene Snowflake-Treiber verwendet, um eine Verbindung zu Snowflake herzustellen, finden Sie unter `Beispiele für Snowflake-Verbindungen<https://github.com/Snowflake-Labs/sf-samples/tree/main/samples/spcs/sf-connection>`_.

Unter Verwendung der von Snowflake bereitgestellten Anmeldeinformationen für Servicebenutzer

Wenn Sie von Snowflake bereitgestellte Anmeldeinformationen für den Service verwenden, müssen Sie folgende Auswirkungen beachten:

  • Jedes Objekt in Snowflake hat eine Eigentümerrolle, d. h. die Rolle, mit der das Objekt erstellt wird. Die Eigentümerrolle eines Service bestimmt die Funktionen, die der Service bei der Interaktion mit Snowflake zulässig hat. Dazu gehören das Ausführen von SQL, der Zugriff auf Stagingbereiche und die Vernetzung zwischen Services.

  • Wenn Sie einen Service erstellen, erstellt Snowflake auch einen Servicebenutzer speziell für diesen Service. Dieser Servicebenutzer hat nur Zugriff auf zwei Rollen: die Rolle des Serviceeigentümers und die ‚PUBLIC‘-Rolle. Die Standardrolle für den Servicebenutzer ist die Rolle des Serviceeigentümers.

Wenn Sie einen Service starten, einschließlich Job-Services, führt Snowflake mehrere Aktionen aus. In jedem Ihrer Anwendungscontainer ermöglicht Snowflake dem Containercode die Verwendung von Treibern für die Verbindung zu Snowflake und die Ausführung von SQL. Das ist vergleichbar mit jedem anderen Code auf Ihrem Computer, der eine Verbindung zu Snowflake herstellt. Die folgende Liste zeigt die Aktionen, die Snowflake ausführt, wenn Sie einen Service starten:

  • Stellt Anmeldeinformationen bereit (ein OAuth-Token) im Container in der Datei /snowflake/session/token. Der Containercode verwendet diese Anmeldeinformationen, um sich als Dienstbenutzer zu authentifizieren. Dieses OAuth-Token kann nicht außerhalb von Snowpark Container Services verwendet werden.

  • Snowflake stellt die folgenden Umgebungsvariablen zur Verfügung, mit denen Sie einen Snowflake-Client in Ihrem Servicecode konfigurieren können:

    • SNOWFLAKE_ACCOUNT: Diese Variable ist auf den Konto-Locator für das Snowflake-Konto eingestellt, unter dem der Service derzeit läuft.

    • SNOWFLAKE_HOST: Diese Variable liefert den Hostnamen, der für die Verbindung zu Snowflake verwendet wird.

Wenn Sie als Servicebenutzer eine Verbindung zu Snowflake herstellen, muss der Containercode SNOWFLAKE_HOST, SNOWFLAKE_ACCOUNTund das OAuth-Token verwenden. Das OAuth-Token kann nicht ohne SNOWFLAKE_HOST verwendet werden.

Beispiel

In Tutorial 2 (siehe main.py) liest der Code die Umgebungsvariablen wie im folgenden Beispiel gezeigt:

SNOWFLAKE_ACCOUNT = os.getenv('SNOWFLAKE_ACCOUNT')
SNOWFLAKE_HOST = os.getenv('SNOWFLAKE_HOST')
Copy

Der Code übergibt diese Variablen an einen Verbindungserstellungscode für den Snowflake-Client Ihrer Wahl. Der Container verwendet diese Anmeldeinformationen, um eine neue Sitzung mit der Eigentümerrolle als Primärrolle zu erstellen, um Abfragen auszuführen. Das folgende Beispiel zeigt den Code, der mindestens zum Erstellen einer Snowflake-Verbindung in Python erforderlich ist:

def get_login_token():
  with open('/snowflake/session/token', 'r') as f:
    return f.read()

conn = snowflake.connector.connect(
  host = os.getenv('SNOWFLAKE_HOST'),
  account = os.getenv('SNOWFLAKE_ACCOUNT'),
  token = get_login_token(),
  authenticator = 'oauth'
)
Copy

Beachten Sie die folgenden Details zu diesem OAuth-Token:

  • Snowflake aktualisiert den Inhalt der Datei /snowflake/session/token alle paar Minuten. Jedes Token ist bis zu eine Stunde lang gültig. Nachdem sich ein Container erfolgreich mit Snowflake verbunden hat, gilt die Ablaufzeit nicht mehr für die Verbindung (wie bei allen Sitzungen, die Benutzende direkt erstellen).

  • Dieses OAuth-Token ist nur innerhalb des jeweiligen Snowflake-Dienstes gültig. Sie können das OAuth-Token nicht kopieren und außerhalb des Services verwenden.

  • Wenn Sie das OAuth-Token zum Verbinden verwenden, wird eine neue Sitzung erstellt. Das OAuth-Token ist mit keiner bestehenden SQL-Sitzung verbunden.

    Bemerkung

    Ein wesentlicher Unterschied zwischen dem Ausführen von gespeicherten Prozeduren und dem Ausführen eines Services besteht darin, dass gespeicherte Prozeduren in der gleichen Sitzung ausgeführt werden wie der SQL-Code, der die Prozeduren ausführt. Aber jedes Mal, wenn ein Container eine neue Verbindung aufbaut, wird eine neue Sitzung erstellt.

Um die von einem bestimmten Dienstbenutzer erstellten Abfragen einzusehen, können Sie die Rolle ACCOUNTADMIN verwenden und den Abfrageverlauf anzeigen. Der Benutzername des Dienstbenutzers wird in den folgenden Formen angezeigt:

  • Bei einem Service, der vor dem Release 8.35 des Servers erstellt wurde, hat der Dienstbenutzer das Format SF$SERVICE$unique-id.

  • Bei einem Service, der nach dem Release 8.35 des Servers erstellt wurde, ist der Dienstbenutzer derselbe wie der Name des Services.

Bemerkung

Die Eigentümerrolle eines Service bezieht sich auf die Rolle, die den Service erstellt hat. Sie können auch eine oder mehrere Servicerollen definieren, um den Zugriff auf die Endpunkte zu verwalten, die der Service bereitstellt. Weitere Informationen dazu finden Sie unter Verwaltung dienstbezogener Berechtigungen.

Allgemeine Informationen zur Verwendung der von Snowflake bereitgestellten Aufruferanmeldeinformationen (Aufruferrechte)

In bestimmten Anwendungsszenarien kann es erforderlich sein, dass Sie Abfragen im Kontext des Endbenutzers und nicht des Servicebenutzers ausführen müssen. In diesem Kontext wird das Aufruferrechte-Feature verwendet.

Nehmen wir zum Beispiel an, Sie erstellen einen Service, der einen öffentlichen Endpunkt für eine Webanwendung bereitstellt, die ein Dashboard mit in Snowflake gespeicherten Daten anzeigt. Sie gewähren anderen Benutzenden in Ihrem Snowflake-Konto Zugriff auf das Dashboard (indem Sie ihnen die Servicerolle zuweisen). Wenn sich Benutzende anmelden, zeigt das Dashboard nur die Daten an, für die diese Benutzenden eine Zugriffsberechtigung haben.

Da Container jedoch standardmäßig Abfragen unter Verwendung des Servicebenutzers und der Eigentümerrolle des Service ausführen, zeigt das Dashboard die Daten an, auf die die Eigentümerrolle des Service Zugriff hat, unabhängig davon, welcher Endbenutzer mit dem Endpunkt verbunden ist. Daher ist das Dashboard nicht auf die Daten beschränkt, auf die die Benutzenden Zugriff haben, sodass die angemeldeten Benutzenden Daten sehen können, auf die sie keinen Zugriff haben sollten.

Um das Dashboard so einzuschränken, dass nur Daten angezeigt werden, auf die die angemeldeten Benutzenden Zugriff haben, müssen die Anwendungscontainer SQL mit den Berechtigungen der Endbenutzenden ausführen. Sie können dies aktivieren, indem Sie die Aufruferrechte in der Anwendung verwenden.

Bemerkung

  • Das Aufruferrechte-Feature wird nur unterstützt, wenn der Zugriff auf einen Dienst über den Netzwerkeingang erfolgt. Das Feature ist nicht verfügbar, wenn Sie eine Servicefunktion für den Zugriff auf den Service verwenden.

  • Das Aufruferrechte-Feature wird derzeit in Snowflake Native App (Apps mit Containern nicht) unterstützt.

Konfigurieren der Aufruferrechte für Ihren Service

Die Konfiguration der Aufruferrechte für Ihre Anwendung ist ein zweistufiges Verfahren.

  1. Setzen Sie in der Servicespezifikation executeAsCaller auf true, wie im folgenden Spezifikationsfragment dargestellt:

    spec:
      containers:
      ...
    capabilities:
      securityContext:
        executeAsCaller: true
    
    Copy

    Diese Einstellung teilt Snowflake mit, dass die Anwendung beabsichtigt, die Aufruferrechte zu verwenden und veranlasst Snowflake, den Sf-Context-Current-User-Token-Header in jede eingehende Anfrage einzufügen, bevor die Anfrage an den Anwendungscontainer gesendet wird. Dieses Benutzer-Token erleichtert die Ausführung der Abfrage als aufrufender Benutzer. Wenn nichts angegeben wird, ist executeAsCaller standardmäßig auf false eingestellt.

    Die Angabe der Option executeAsCaller wirkt sich nicht auf die Möglichkeit des Services aus, Abfragen in der Servicebenutzerrolle und der Eigentümerrolle des Services auszuführen. Wenn executeAsCaller aktiviert ist, hat der Dienst die Möglichkeit, sich sowohl als aufrufender Benutzer als auch als Dienstbenutzer mit Snowflake zu verbinden.

  2. Um eine Snowflake-Verbindung im Namen des aufrufenden Benutzers herzustellen, aktualisieren Sie Ihren Anwendungscode, um ein Anmeldetoken zu erstellen, das sowohl das OAuth-Token, das Snowflake dem Service bereitgestellt hat, als auch das Benutzer-Token aus dem Sf-Context-Current-User-Token-Header enthält.

    Das Anmeldetoken muss diesem Format entsprechen: <service-oauth-token>.<Sf-Context-Current-User-Token>.

    Diese Änderung wird in dem folgenden Python-Codefragment veranschaulicht:

    # Environment variables below will be automatically populated by Snowflake.
    SNOWFLAKE_ACCOUNT = os.getenv("SNOWFLAKE_ACCOUNT")
    SNOWFLAKE_HOST = os.getenv("SNOWFLAKE_HOST")
    
    def get_login_token():
        with open("/snowflake/session/token", "r") as f:
            return f.read()
    
    def get_connection_params(ingress_user_token = None):
        # start a Snowflake session as ingress user
        # (if user token header provided)
        if ingress_user_token:
            logger.info("Creating a session on behalf of the current user.")
            token = get_login_token() + "." + ingress_user_token
        else:
            logger.info("Creating a session as the service user.")
            token = get_login_token()
    
        return {
            "account": SNOWFLAKE_ACCOUNT,
            "host": SNOWFLAKE_HOST,
            "authenticator": "oauth",
            "token": token
        }
    
    def run_query(request, query):
        ingress_user_token = request.headers.get('Sf-Context-Current-User-Token')
        # ingress_user_token is None if header not present
        connection_params = get_connection_params(ingress_user_token)
        with Session.builder.configs(connection_params).create() as session:
          # use the session to execute a query.
    
    Copy

Im obigen Beispiel:

  • Die Funktion get_login_token liest die Datei, in die Snowflake das OAuth-Token für den zu verwendenden Container kopiert hat.

  • Die Funktion get_connection_params konstruiert ein Token durch Verkettung des OAuth-Token und des Benutzertoken aus dem Sf-Context-Current-User-Token-Header. Die Funktion nimmt dieses Token in ein Verzeichnis von Parametern auf, die die Anwendung für die Verbindung mit Snowflake verwendet.

Bemerkung

Wenn ein Service die Aufruferrechte nutzt, kann er sich als mehrere Benutzende mit Snowflake verbinden. Sie sind für die Verwaltung des Zugriffs auf Ressourcen verantwortlich, die nicht von Snowflake verwaltet werden.

Zum Beispiel speichert in Streamlit-Apps das Objekt st.connection die Verbindung automatisch mithilfe von st.cache_resource im globalen Status, sodass es in verschiedenen Streamlit-Sitzungen zugänglich ist, die von verschiedenen Benutzenden gestartet werden. Wenn Sie Aufruferrechte verwenden, sollten Sie st.session_state verwenden, um Verbindungen für einzelne Sitzungen zu speichern und so zu vermeiden, dass Verbindungen zwischen Benutzenden gemeinsam genutzt werden.

Ein Beispiel mit einer Schritt-für-Schritt-Anleitung finden Sie unter Erstellen eines Dienstes mit aktivierten Aufruferrechten.

Zugriff auf einen Dienst mit konfigurierten Aufruferrechten

Konfiguration der Aufruferrechte bedeutet, dass Ihr Service im Namen des Aufrufers eine Snowflake-Verbindung aufbaut. Die Art und Weise, wie Sie sich bei den Eingangsendpunkten des Services anmelden (programmgesteuert oder über einen Browser), bleibt unverändert. Nach der Anmeldung gelten die folgenden Verhaltensweisen und Optionen:

  • Zugriff auf einen öffentlichen Endpunkt über einen Browser: Nachdem Sie sich bei einem Endpunkt angemeldet haben, stellt der Service im Namen der anrufenden Benutzenden mit deren Standardrolle eine Verbindung zu Snowflake her. Wenn keine Standardrolle für den Benutzer konfiguriert ist, wird die Rolle PUBLIC verwendet.

  • Programmgesteuerter Zugriff auf einen öffentlichen Endpunkt: Bei der programmgesteuerten Anmeldung bei einem Endpunkt mit dem JWT-Token können Sie optional den Parameter scope setzen, um die zu aktivierende Rolle anzugeben

Nachdem ein Dienst die Verbindung zu Snowflake mit Aufruferrechten im Namen des Aufrufers hergestellt hat, wird ein Umschalten zwischen den Rollen derzeit nicht unterstützt. Wenn Ihre Anwendung verschiedene Rollen für den Zugriff auf verschiedene Objekte benötigt, müssen Sie die Standardeigenschaft der Sekundärrollen der Benutzenden ändern.

  • Um die Benutzenden so einzurichten, dass alle Sekundärrollen standardmäßig aktiv sind, verwenden Sie den Befehl ALTER USER, um die DEFAULT_SECONDARY_ROLES Eigenschaft der Benutzenden auf (‚ALL‘) einzustellen, wie im folgenden Beispiel gezeigt:

ALTER USER my_user SET DEFAULT_SECONDARY_ROLES = ( 'ALL' );
Copy

Verwalten von Aufruferberechtigungen für einen Dienst

Wenn ein Service eine Sitzung mit Aufruferrechten erstellt, arbeitet die Sitzung als aufrufender Benutzer (nicht als Servicebenutzer). Wenn ein Vorgang über diese Sitzung durchgeführt wird, wendet Snowflake nacheinander zwei Berechtigungsprüfungen an:

  1. Die erste Berechtigungsprüfung erfolgt so, als hätten die Benutzenden die Sitzung direkt erstellt. Diese Prüfung ist Teil der normalen Berechtigungsprüfungen, die Snowflake für Benutzende durchführt.

  2. Die zweite Berechtigungsprüfung verifiziert, dass der Service den Vorgang im Namen eines Benutzers durchführen darf. Snowflake überprüft dies, indem sichergestellt wird, dass der Rolle des Serviceeigentümers die erforderlichen Aufruferberechtigungen gewährt wurden.

In einer Sitzung mit Aufruferrechten müssen sowohl die normale Berechtigungsprüfung als auch die Prüfung der Aufruferrechte der Rolle des Diensteigentümers die Operation erlauben. Dies wird als eingeschränkte Aufruferrechte bezeichnet. Standardmäßig hat der Dienst keine Berechtigung, etwas im Namen eines Benutzers zu tun. Sie müssen dem Dienst explizit Aufruferrechte gewähren, damit er mit den Berechtigungen des Aufrufers ausgeführt werden kann.

Nehmen wir zum Beispiel an, dass die/der Benutzende U1 die Rolle R1 verwendet, die die Berechtigung SELECT für die Tabelle T1 hat. Wenn sich U1 bei dem öffentlichen Endpunkt Ihres Dienstes (example_service) anmeldet, der so konfiguriert ist, dass er die Aufruferrechte verwendet, stellt der Dienst dann im Namen von U1 eine Verbindung zu Snowflake her.

Damit der Dienst die Tabelle T1 im Namen von U1 abfragen kann, müssen Sie der Rolle des Diensteigentümers die folgenden Berechtigungen erteilen:

  • Berechtigungen zur Auflösung des Tabellennamens, indem einem Aufrufer eine Berechtigung gewährt wird, die es dem Dienst ermöglicht, mit der USAGE-Berechtigung auf der Datenbank und dem Schema für diese Tabelle zu arbeiten.

  • Berechtigung zur Verwendung eines Warehouse, um Abfragen auszuführen, indem einem Aufrufer eine Berechtigung gewährt wird, die es dem Dienst ermöglicht, mit der entsprechende USAGE-Berechtigung auf dem Warehouse zu arbeiten.

  • Berechtigungen zur Abfrage der Tabelle, indem einem Aufrufer eine Berechtigung gewährt wird, die es dem Dienst ermöglicht, mit der SELECT-Berechtigung auf der Tabelle T1 ausgeführt zu werden.

Das folgende Beispiel zeigt, wie Sie der Eigentümerrolle des Services diese Berechtigungen zuweisen:

-- Permissions to resolve the table's name.
GRANT CALLER USAGE ON DATABASE <db_name> TO ROLE <service_owner_role>;
GRANT CALLER USAGE ON SCHEMA <schema_name> TO ROLE <service_owner_role>;
-- Permissions to use a warehouse
GRANT CALLER USAGE ON WAREHOUSE <warehouse_name> TO ROLE <service_owner_role>;
-- Permissions to query the table.
GRANT CALLER SELECT ON TABLE T1 TO ROLE <service_owner_role>;
Copy

Jede Rolle in Ihrem Konto, die über die globale Berechtigung MANAGE CALLER GRANT verfügt, kann Aufruferberechtigungen gewähren. Weitere Informationen über Aufruferrechte finden Sie unter GRANT CALLER und Eingeschränkte Aufruferrechte.

Beispiel

Hier finden Sie ein Beispiel für einen Service, der bei der Ausführung von SQL-Abfragen im Namen von Benutzenden das Aufruferrechte-Feature verwendet. Weitere Informationen finden Sie unter Erstellen eines Dienstes mit aktivierten Aufruferrechten.

Herstellen einer Verbindung zu Snowflake mit anderen Anmeldeinformationen

Sie können auch andere Formen der Authentifizierung verwenden, um eine Verbindung zu Snowflake herzustellen, nicht nur das von Snowflake bereitgestellte OAuth-Token. Dazu erstellen Sie eine Integration für den externen Zugriff (EAI, External Access Integration), die es Ihrem Container ermöglicht, eine Verbindung zu Snowflake herzustellen, als ob der Container außerhalb von Snowflake ausgeführt wird und sich über das Internet verbindet. Wenn Sie sich auf diese Weise verbinden, müssen Sie nicht den Host konfigurieren, der vom Client verwendet wird.

Bemerkung

Da diese Verbindungen einen EAI durchlaufen, setzt die Snowflake-Authentifizierung auch Netzwerkrichtlinien durch. Wenn Ihr Unternehmen Netzwerkrichtlinien erfordert, wird das Verbinden mit anderen Anmeldeinformationen nicht unterstützt.

Bei der folgenden Verbindung werden zur Authentifizierung beispielsweise Benutzername und Kennwort angegeben:

conn = snowflake.connector.connect(
  account = '<acct-name>',
  user = '<user-name>',
  password = '<password>'
)
Copy

Die Verwendung eines Standard-Hostnamens erfordert eine Integration für den externen Zugriff mit einer Netzwerkregel, die den Zugriff von Ihrem Service auf den Snowflake-Internet-Hostnamen Ihres Kontos gestattet. Wenn Ihr Kontoname beispielsweise MYACCOUNT in der Organisation MYORG lautet, dann lautet der Hostname myorg-myaccount.snowflakecomputing.com. Weitere Informationen dazu finden Sie unter Konfigurieren des Netzwerkausgangs. Privatelink-Hostnamen werden nicht unterstützt

  • Erstellen Sie eine Netzwerkregel, die einen Abgleich mit Snowflake-API-Hostnamen Ihres Kontos vornimmt:

    CREATE OR REPLACE NETWORK RULE snowflake_egress_access
      MODE = EGRESS
      TYPE = HOST_PORT
      VALUE_LIST = ('myorg-myaccount.snowflakecomputing.com');
    
    Copy
  • Erstellen Sie eine Integration unter Verwendung der obigen Netzwerkregel:

    CREATE EXTERNAL ACCESS INTEGRATION snowflake_egress_access_integration
      ALLOWED_NETWORK_RULES = (snowflake_egress_access)
      ENABLED = TRUE;
    
    Copy

Konfiguration des Datenbank- und Schemakontextes für das Ausführen von SQL

Neben der Bereitstellung von Anmeldeinformationen stellt Snowflake auch den Datenbank- und Schemakontext bereit, in dem der Service erstellt wird. Der Containercode kann diese Informationen zur Ausführung von SQL im gleichen Datenbank- und Schemakontext wie der Service verwenden.

In diesem Abschnitt werden zwei Konzepte erläutert:

  • Die Logik, mit der Snowflake Datenbank und Schema bestimmt, in dem Ihr Dienst erstellt werden soll.

  • Die Methode, mit der Snowflake diese Informationen an Ihre Container weitergibt, sodass der Containercode SQL im gleichen Datenbank- und Schemakontext ausführen kann.

Snowflake verwendet den Dienstnamen, um die Datenbank und das Schema zu bestimmen, in denen ein Dienst erstellt werden soll:

  • Beispiel 1: In den folgenden Befehlen CREATE SERVICE und EXECUTE JOB SERVICE gibt der Dienstname nicht explizit einen Datenbank- und Schemanamen an. Snowflake erstellt den Dienst und den Jobdienst in der aktuellen Datenbank und dem aktuellen Schema.

    -- Create a service.
    CREATE SERVICE test_service IN COMPUTE POOL ...
    
    -- Execute a job service.
    EXECUTE JOB SERVICE
      IN COMPUTE POOL tutorial_compute_pool
      NAME = example_job_service ...
    
    Copy
  • Beispiel 2: In den folgenden Befehlen CREATE SERVICE und EXECUTE JOB SERVICE enthält der Dienstname einen Datenbank- und einen Schemanamen. Snowflake erstellt den Dienst und den Jobdienst in der angegebenen Datenbank (test_db) und dem angegebenen Schema (test_schema), unabhängig vom aktuellen Schema.

    -- Create a service.
    CREATE SERVICE test_db.test_schema.test_service IN COMPUTE POOL ...
    
    -- Execute a job service.
    EXECUTE JOB SERVICE
      IN COMPUTE POOL tutorial_compute_pool
      NAME = test_db.test_schema.example_job_service ...
    
    Copy

Wenn Snowflake einen Dienst startet, werden den ausgeführten Containern die Datenbank- und Schemainformationen über die folgenden Umgebungsvariablen zur Verfügung gestellt:

  • SNOWFLAKE_DATABASE

  • SNOWFLAKE_SCHEMA

Ihr Containercode kann Umgebungsvariablen im Verbindungscode verwenden, um die zu verwendende Datenbank und das Schema zu bestimmen, wie im folgenden Beispiel gezeigt:

conn = snowflake.connector.connect(
  host = os.getenv('SNOWFLAKE_HOST'),
  account = os.getenv('SNOWFLAKE_ACCOUNT'),
  token = get_login_token(),
  authenticator = 'oauth',
  database = os.getenv('SNOWFLAKE_DATABASE'),
  schema = os.getenv('SNOWFLAKE_SCHEMA')
)
Copy

Beispiel

In Tutorial 2 erstellen Sie einen Snowflake-Jobdienst, der sich mit Snowflake verbindet und SQL-Anweisungen ausführt. Die folgenden Schritte fassen zusammen, wie der Tutorial-Code die Umgebungsvariablen verwendet:

  1. Bei der grundlegenden Einrichtung (siehe Abschnitt Grundlegende Einrichtung) erstellen Sie Ressourcen, einschließlich einer Datenbank und eines Schemas. Sie legen auch die aktuelle Datenbank und das aktuelle Schema für die Sitzung fest:

    USE DATABASE tutorial_db;
    ...
    USE SCHEMA data_schema;
    
    Copy
  2. Nachdem Sie einen Jobdienst erstellt haben (durch Ausführen von EXECUTE JOB SERVICE), startet Snowflake den Container und setzt die folgenden Umgebungsvariablen im Container auf die aktuelle Datenbank und das aktuelle Schema der Sitzung:

    • SNOWFLAKE_DATABASE ist auf „TUTORIAL_DB“ gesetzt.

    • SNOWFLAKE_SCHEMA ist auf „DATA_SCHEMA“ gesetzt.

  3. Der Jobcode (siehe main.py in Tutorial 2) liest diese Umgebungsvariablen aus:

    SNOWFLAKE_DATABASE = os.getenv('SNOWFLAKE_DATABASE')
    SNOWFLAKE_SCHEMA = os.getenv('SNOWFLAKE_SCHEMA')
    
    Copy
  4. Der Jobcode legt die Datenbank und das Schema als Kontext fest, in dem die SQL-Anweisungen ausgeführt werden (Funktion run_job() in main.py):

    {
       "account": SNOWFLAKE_ACCOUNT,
       "host": SNOWFLAKE_HOST,
       "authenticator": "oauth",
       "token": get_login_token(),
       "warehouse": SNOWFLAKE_WAREHOUSE,
       "database": SNOWFLAKE_DATABASE,
       "schema": SNOWFLAKE_SCHEMA
    }
    ...
    
    Copy

    Bemerkung

    SNOWFLAKE_ACCOUNT SNOWFLAKE_HOST, SNOWFLAKE_DATABASE, SNOWFLAKE_SCHEMA sind Umgebungsvariablen, die Snowflake für den Anwendungscontainer generiert, allerdings nicht SNOWFLAKE_WAREHOUSE (der Anwendungscode von Tutorial 2 erstellt diese Variable, da Snowflake keinen Warehouse-Namen an einen Container übergibt).

Angeben des Warehouses für Ihren Container

Wenn Ihr Dienst eine Verbindung zu Snowflake herstellt, um eine Abfrage in einem Snowflake-Warehouse auszuführen, haben Sie die folgenden Optionen für die Angabe des Warehouses:

  • Warehouse in Ihrem Anwendungscode angeben. Geben Sie ein Warehouse als Teil der Verbindungskonfiguration an, wenn Sie eine Snowflake-Sitzung zum Ausführen von Abfragen in Ihrem Code starten. Ein Beispiel dazu finden Sie unter Tutorial 2.

  • Standard-Warehouse beim Erstellen eines Dienstes angeben. Geben Sie den optionalen Parameter QUERY_WAREHOUSE im Befehl CREATE SERVICE oder EXECUTE JOB SERVICE an, um ein Standard-Warehouse bereitzustellen. Wenn Ihr Anwendungscode kein Warehouse als Teil der Verbindungskonfiguration bereitstellt, verwendet Snowflake das Standard-Warehouse. Verwenden Sie den Befehl ALTER SERVICE, um das Standard-Warehouse zu ändern.

    Bemerkung

    Das Warehouse, das mit dem QUERY_WAREHOUSE-Parameter angegeben wurde, ist der Standard nur für Servicebenutzer. Wenn der Service im Namen eines anderen Benutzers eine Verbindung zu Snowflake herstellt – im Kontext des Szenarios der Aufruferrechte –, verwendet Snowflake das Standard-Warehouse des Benutzers.

Wenn Sie ein Warehouse mit beiden Methoden angeben, wird das im Anwendungscode angegebene Warehouse verwendet.

Abfrageverlauf von Benutzern des Zugriffs auf den Service

Sie können Abfragen finden, die von Ihrem Service als Servicebenutzer ausgeführt wurden, indem Sie die Funktion Ansicht QUERY_HISTORY oder QUERY_HISTORY filtern, wobei user_type SNOWFLAKE_SERVICE ist.

Beispiel 1: Abrufen von Abfragen, die von einem Dienst ausgeführt werden.

SELECT *
FROM snowflake.account_usage.query_history
WHERE user_type = 'SNOWFLAKE_SERVICE'
AND user_name = '<service_name>'
AND user_database_name = '<service_db_name>'
AND user_schema_name = '<service_schema_name>'
order by start_time;
Copy

Für die WHERE-Klausel gilt:

  • user_name = '<service_name>': Sie geben den Dienstnamen als Benutzernamen an, da ein Dienst Abfragen als Dienstbenutzer ausführt und der Name des Dienstbenutzers mit dem Dienstnamen identisch ist.

  • user_type = 'SNOWFLAKE_SERVICE' und user_name = '<service_name>': Dies schränkt das Abfrageergebnis so ein, dass nur von einem Dienst ausgeführte Abfragen abgerufen werden.

  • user_database_name und user_schema_name: Für einen Benutzer eines Dienstes sind dies die Datenbank und das Schema des Dienstes.

Sie können die gleichen Ergebnisse erzielen, indem Sie die Funktion QUERY_HISTORY aufrufen.

SELECT *
FROM TABLE(<service_db_name>.information_schema.query_history())
WHERE user_database_name = '<service_db_name>'
AND user_schema_name = '<service_schema_name>'
AND user_type = 'SNOWFLAKE_SERVICE'
AND user_name = '<service_name>'
order by start_time;
Copy

Für die WHERE-Klausel gilt:

  • user_type = 'SNOWFLAKE_SERVICE' und user_name = '<service_name>' schränken das Abfrageergebnis so ein, dass nur von einem Dienst ausgeführte Abfragen abgerufen werden.

  • user_database_name- und user_schema_name-Namen (für einen Dienstbenutzer) sind die Datenbank und das Schema des Dienstes.

Beispiel 2: Von Diensten ausgeführte Abfragen und die entsprechenden Dienstinformationen abrufen.

SELECT query_history.*, services.*
FROM snowflake.account_usage.query_history
JOIN snowflake.account_usage.services
ON query_history.user_name = services.service_name
AND query_history.user_schema_id = services.service_schema_id
AND query_history.user_type = 'SNOWFLAKE_SERVICE'
Copy

Die Abfrage verknüpft die Ansichten QUERY_HISTORY und SERVICES, um Informationen über die Abfragen und die Dienste, die die Abfragen ausführten, abzurufen. Beachten Sie Folgendes:

  • Bei Abfragen, die von Diensten ausgeführt werden, ist query_history.user_name der Name des Dienstbenutzers, der mit dem Dienstnamen übereinstimmt.

  • Die Abfrage verbindet die Ansichten anhand des Schemas IDs (nicht des Schemanamens), um sicherzustellen, dass Sie sich auf dasselbe Schema beziehen. Denn wenn Sie ein Schema löschen und neu erstellen, ändert sich das Schema ID, aber der Name bleibt derselbe.

Sie können der Abfrage optionale Filter hinzufügen. Beispiel:

  • query_history-Filter, um nur Dienste abzurufen, die bestimmte Abfragen ausgeführt haben.

  • services-Filter, um nur Abfragen abzurufen, die von bestimmten Diensten ausgeführt wurden.

Beispiel 3: Abrufen von Dienstbenutzerinformationen für jeden Dienst.

SELECT services.*, users.*
FROM snowflake.account_usage.users
JOIN snowflake.account_usage.services
ON users.name = services.service_name
AND users.schema_id = services.service_schema_id
AND users.type = 'SNOWFLAKE_SERVICE'
Copy

Die Abfrage verbindet die Ansichten SERVICES und USERS im Schema ACCOUNT_USAGE, um Dienste und Benutzerinformationen abzurufen. Beachten Sie Folgendes:

  • Wenn ein Dienst Abfragen ausführt, führt er die Abfragen als Dienstbenutzer aus, und der Name des Dienstbenutzers ist derselbe wie der Dienstname. Daher geben Sie die Join-Bedingung an: users.name = services.service_name.

  • Dienstnamen sind nur innerhalb eines Schemas eindeutig. Daher gibt die Abfrage die Join-Bedingung (users.schema_id = services.service_schema_id) an, um sicherzustellen, dass jeder Dienstbenutzer mit dem spezifischen Dienst abgeglichen wird, zu dem er gehört (und nicht mit einem anderen gleichnamigen Dienst, der in verschiedenen Schemas läuft).