Snowflake
This guide walks you through connecting Snowflake to Solid so you can get insights into your data lineage, usage, and quality.
Overview
Solid requires access to:
- The schema of your Snowflake datasets
- Query logs from the Query History table
- [Optional] Read-only grants for data profiling
Note: You will need ACCOUNTADMIN role to create the Solid role and user.
You have two options for connecting Snowflake to Solid:
| Option | Best For | What You'll Do |
|---|---|---|
| Automatic Pull (Recommended) | Ongoing use and continuous monitoring | Set up a service user that runs automatically |
| Manual Pull | Quick proof of concept or one-time setup | Export data manually and upload it |
Option 1: Automatic Pull (Recommended)
Best for: Production use with continuous monitoring and updates.
What This Does
This script creates a dedicated service user that Solid uses to automatically pull metadata from your Snowflake account. The script is modular, allowing you to choose whether to include read-only grants based on your use case.
The warehouse is configured to:
- Use XSMALL size (minimal cost)
- Auto-suspend after 5 minutes of inactivity
- Auto-resume when needed
Prerequisites
- You need ACCOUNTADMIN role to run this script
- Replace
<your_database>with your actual database name
Configuration Variables
The script defines several variables to customize the setup:
| Variable | Default | Description |
|---|---|---|
solid_username | SOLID_DATA | The name for the new Snowflake user |
solid_warehouse_size | XSMALL | The compute size for the new virtual warehouse |
solid_warehouse_name | SOLID_DATA_WH | The name for the new virtual warehouse |
solid_role_name | SOLID_DATA_ROLE | The name for the new Snowflake role |
database_to_monitor | (must be replaced) | The database you want Solid to monitor |
Setup Script
-- ==========================================
-- 1. CONFIGURATION & VARIABLES
-- ==========================================
set solid_username='SOLID_DATA';
set solid_warehouse_size='XSMALL';
set solid_warehouse_name='SOLID_DATA_WH';
set solid_role_name='SOLID_DATA_ROLE';
set database_to_monitor=''; -- REPLACE THIS WITH YOUR DATABASE NAME
USE ROLE ACCOUNTADMIN;
-- ==========================================
-- 2. CORE SETUP: Role, User, and Warehouse
-- ==========================================
-- Create virtual warehouse (Auto-suspends after 5 min to optimize cost)
CREATE WAREHOUSE IF NOT EXISTS identifier($solid_warehouse_name)
WAREHOUSE_SIZE=$solid_warehouse_size
INITIALLY_SUSPENDED=TRUE
AUTO_SUSPEND = 5
AUTO_RESUME = TRUE;
-- Create the custom role for Solid
CREATE ROLE IF NOT EXISTS identifier($solid_role_name);
-- Create the Service User and assign the role
CREATE USER IF NOT EXISTS identifier($solid_username)
DEFAULT_ROLE=$solid_role_name
TYPE=SERVICE;
GRANT ROLE identifier($solid_role_name) TO USER identifier($solid_username);
-- ==========================================
-- 3. GRANT REQUIRED PERMISSIONS
-- ==========================================
-- Warehouse Permissions
-- OPERATE: Allows starting, stopping, and resizing the warehouse
-- USAGE: Allows using the warehouse to execute queries
-- MONITOR: Allows viewing warehouse status, usage statistics, and query history
GRANT OPERATE, USAGE, MONITOR ON WAREHOUSE identifier($solid_warehouse_name)
TO ROLE identifier($solid_role_name);
-- Allow access to internal query history and metadata
GRANT IMPORTED PRIVILEGES ON DATABASE "SNOWFLAKE"
TO ROLE identifier($solid_role_name);
-- Grant access to the monitored database
GRANT USAGE, MONITOR ON DATABASE identifier($database_to_monitor)
TO ROLE identifier($solid_role_name);
GRANT USAGE, MONITOR ON ALL SCHEMAS IN DATABASE identifier($database_to_monitor)
TO ROLE identifier($solid_role_name);
GRANT USAGE, MONITOR ON FUTURE SCHEMAS IN DATABASE identifier($database_to_monitor)
TO ROLE identifier($solid_role_name);
-- ==========================================
-- 4. REFERENCE GRANTS PROCEDURE
-- ==========================================
-- Logic to ensure lineage visibility even if schema-level future grants exist
-- REFERENCES privilege is vital for foreign key constraints and metadata lookups
-- but does not allow data access
USE DATABASE identifier($database_to_monitor);
CREATE OR REPLACE PROCEDURE GRANT_REFERENCES_TO_SOLID()
RETURNS VARCHAR LANGUAGE javascript EXECUTE AS CALLER
AS
$$
snowflake.createStatement({sqlText: `use database identifier($database_to_monitor)`}).execute();
var show_future_grants = snowflake.createStatement({sqlText: `SHOW FUTURE GRANTS IN DATABASE identifier($database_to_monitor)`}).execute();
var schema_future_grants = snowflake.createStatement({sqlText: `select * from TABLE(RESULT_SCAN('${show_future_grants.getQueryId()}')) where "grant_on" = 'SCHEMA'`}).execute();
if (schema_future_grants.getRowCount() > 0) {
var schemas_to_grant = snowflake.createStatement({ sqlText:`select * from information_schema.SCHEMATA where SCHEMA_NAME <> 'INFORMATION_SCHEMA'`}).execute();
var granted_schemas = "";
while(schemas_to_grant.next()) {
table_schema = schemas_to_grant.getColumnValue("SCHEMA_NAME");
snowflake.createStatement({ sqlText:`GRANT REFERENCES ON ALL TABLES IN SCHEMA ${table_schema} TO ROLE identifier($solid_role_name)`}).execute();
snowflake.createStatement({ sqlText:`GRANT REFERENCES ON ALL VIEWS IN SCHEMA ${table_schema} TO ROLE identifier($solid_role_name)`}).execute();
snowflake.createStatement({ sqlText:`GRANT REFERENCES ON ALL EXTERNAL TABLES IN SCHEMA ${table_schema} TO ROLE identifier($solid_role_name)`}).execute();
snowflake.createStatement({ sqlText:`GRANT MONITOR ON ALL DYNAMIC TABLES IN SCHEMA ${table_schema} TO ROLE identifier($solid_role_name)`}).execute();
snowflake.createStatement({ sqlText:`GRANT REFERENCES ON FUTURE TABLES IN SCHEMA ${table_schema} TO ROLE identifier($solid_role_name)`}).execute();
snowflake.createStatement({ sqlText:`GRANT REFERENCES ON FUTURE VIEWS IN SCHEMA ${table_schema} TO ROLE identifier($solid_role_name)`}).execute();
snowflake.createStatement({ sqlText:`GRANT REFERENCES ON FUTURE EXTERNAL TABLES IN SCHEMA ${table_schema} TO ROLE identifier($solid_role_name)`}).execute();
snowflake.createStatement({ sqlText:`GRANT MONITOR ON FUTURE DYNAMIC TABLES IN SCHEMA ${table_schema} TO ROLE identifier($solid_role_name)`}).execute();
granted_schemas += table_schema + "; "
}
return `Granted references for schemas ${granted_schemas}`;
}
snowflake.createStatement({ sqlText: `GRANT REFERENCES ON ALL TABLES IN DATABASE identifier($database_to_monitor) TO ROLE identifier($solid_role_name)`}).execute();
snowflake.createStatement({ sqlText: `GRANT REFERENCES ON ALL VIEWS IN DATABASE identifier($database_to_monitor) TO ROLE identifier($solid_role_name)`}).execute();
snowflake.createStatement({ sqlText: `GRANT REFERENCES ON ALL EXTERNAL TABLES IN DATABASE identifier($database_to_monitor) TO ROLE identifier($solid_role_name)`}).execute();
snowflake.createStatement({ sqlText: `GRANT MONITOR ON ALL DYNAMIC TABLES IN DATABASE identifier($database_to_monitor) TO ROLE identifier($solid_role_name)`}).execute();
snowflake.createStatement({ sqlText: `GRANT REFERENCES ON FUTURE TABLES IN DATABASE identifier($database_to_monitor) TO ROLE identifier($solid_role_name)`}).execute();
snowflake.createStatement({ sqlText: `GRANT REFERENCES ON FUTURE VIEWS IN DATABASE identifier($database_to_monitor) TO ROLE identifier($solid_role_name)`}).execute();
snowflake.createStatement({ sqlText: `GRANT REFERENCES ON FUTURE EXTERNAL TABLES IN DATABASE identifier($database_to_monitor) TO ROLE identifier($solid_role_name)`}).execute();
snowflake.createStatement({ sqlText: `GRANT MONITOR ON FUTURE DYNAMIC TABLES IN DATABASE identifier($database_to_monitor) TO ROLE identifier($solid_role_name)`}).execute();
return `Granted references for database`;
$$;
CALL GRANT_REFERENCES_TO_SOLID();
-- ==========================================
-- 5. SEMANTIC VIEW GRANTS (REQUIRED)
-- ==========================================
-- Allows Solid to create semantic views in the monitored database
-- This grant is required for Solid to function
-- Option A: Grant on all current and future schemas in the database (recommended)
GRANT CREATE SEMANTIC VIEW ON FUTURE SCHEMAS IN DATABASE identifier($database_to_monitor)
TO ROLE identifier($solid_role_name);
-- Option B: Grant on a specific schema only (if you prefer not to grant on all schemas)
-- Replace with the specific schema name
-- GRANT CREATE SEMANTIC VIEW ON SCHEMA identifier($database_to_monitor).
-- TO ROLE identifier($solid_role_name);
-- ==========================================
-- 6. [OPTIONAL] SOLID READ ONLY GRANTS
-- ==========================================
-- Only run this section if you want Solid to perform direct data profiling/quality checks
-- This gives SOLID_DATA_ROLE read-only access to the data within the monitored database
GRANT SELECT ON ALL TABLES IN DATABASE identifier($database_to_monitor)
TO ROLE identifier($solid_role_name);
GRANT SELECT ON ALL VIEWS IN DATABASE identifier($database_to_monitor)
TO ROLE identifier($solid_role_name);
GRANT SELECT ON ALL EXTERNAL TABLES IN DATABASE identifier($database_to_monitor)
TO ROLE identifier($solid_role_name);
GRANT SELECT ON ALL STREAMS IN DATABASE identifier($database_to_monitor)
TO ROLE identifier($solid_role_name);
GRANT SELECT ON ALL DYNAMIC TABLES IN DATABASE identifier($database_to_monitor)
TO ROLE identifier($solid_role_name);
CREATE OR REPLACE PROCEDURE GRANT_SELECT_FUTURES_TO_SOLID()
RETURNS VARCHAR LANGUAGE javascript EXECUTE AS CALLER
AS
$$
snowflake.createStatement({sqlText: `use database identifier($database_to_monitor)`}).execute();
var show_future_grants = snowflake.createStatement({sqlText: `SHOW FUTURE GRANTS IN DATABASE identifier($database_to_monitor)`}).execute();
var schema_future_grants = snowflake.createStatement({sqlText: `select * from TABLE(RESULT_SCAN('${show_future_grants.getQueryId()}')) where "grant_on" = 'SCHEMA'`}).execute();
if (schema_future_grants.getRowCount() > 0) {
var schemas_to_grant = snowflake.createStatement({ sqlText:`select SCHEMA_NAME from information_schema.SCHEMATA where SCHEMA_NAME <> 'INFORMATION_SCHEMA'`}).execute();
while(schemas_to_grant.next()) {
table_schema = schemas_to_grant.getColumnValue("SCHEMA_NAME");
snowflake.createStatement({ sqlText:`GRANT SELECT ON FUTURE TABLES IN SCHEMA ${table_schema} TO ROLE identifier($solid_role_name)`}).execute();
snowflake.createStatement({ sqlText:`GRANT SELECT ON FUTURE VIEWS IN SCHEMA ${table_schema} TO ROLE identifier($solid_role_name)`}).execute();
snowflake.createStatement({ sqlText:`GRANT SELECT ON FUTURE EXTERNAL TABLES IN SCHEMA ${table_schema} TO ROLE identifier($solid_role_name)`}).execute();
snowflake.createStatement({ sqlText:`GRANT SELECT ON FUTURE STREAMS IN SCHEMA ${table_schema} TO ROLE identifier($solid_role_name)`}).execute();
snowflake.createStatement({ sqlText:`GRANT SELECT ON FUTURE DYNAMIC TABLES IN SCHEMA ${table_schema} TO ROLE identifier($solid_role_name)`}).execute();
}
return `Granted future select for schemas`;
}
snowflake.createStatement({ sqlText:`GRANT SELECT ON FUTURE TABLES IN DATABASE identifier($database_to_monitor) TO ROLE identifier($solid_role_name)`}).execute();
snowflake.createStatement({ sqlText:`GRANT SELECT ON FUTURE VIEWS IN DATABASE identifier($database_to_monitor) TO ROLE identifier($solid_role_name)`}).execute();
snowflake.createStatement({ sqlText:`GRANT SELECT ON FUTURE EXTERNAL TABLES IN DATABASE identifier($database_to_monitor) TO ROLE identifier($solid_role_name)`}).execute();
snowflake.createStatement({ sqlText:`GRANT SELECT ON FUTURE STREAMS IN DATABASE identifier($database_to_monitor) TO ROLE identifier($solid_role_name)`}).execute();
snowflake.createStatement({ sqlText:`GRANT SELECT ON FUTURE DYNAMIC TABLES IN DATABASE identifier($database_to_monitor) TO ROLE identifier($solid_role_name)`}).execute();
return `Granted future select for database`;
$$;
CALL GRANT_SELECT_FUTURES_TO_SOLID();How to Use the Script
- Replace Placeholder — Before running, replace
<your_database>with the actual name of the Snowflake database you want Solid to monitor. - Execute in Snowflake — Run the script in your Snowflake worksheet or client.
- Conditional Execution:
- To monitor metadata and schema changes only (lineage, schema drift detection) without reading actual data, run sections 1–5 (stop before Section 6: SOLID READ ONLY GRANTS).
- To also enable data profiling and quality checks, run the full script including Section 6.
Note on Semantic View Grants (Section 5): This grant is required for Solid to function. Option A (recommended) grants permission across all current and future schemas in the database. Option B allows you to restrict the grant to a specific schema if your security policies require more granular control.
Option 2: Manual Pull (Quick Start)
Best for: Testing Solid or if you can't grant direct database access yet.
Steps
- Run the queries below in your Snowflake Query Editor
- Export each result as a CSV file
- Compress the files (ZIP or GZIP)
- Upload to the Solid Azure Storage container
Metadata Collection
Columns
For each database, run the following query. You can choose the relevant schemas or remove the filter in the last line:
SELECT
*,
t1.COMMENT AS COLUMN_COMMENT,
t2.COMMENT AS TABLE_COMMENT
FROM
{DB}.INFORMATION_SCHEMA.COLUMNS t1
LEFT JOIN {DB}.INFORMATION_SCHEMA.TABLES t2 ON
t1.TABLE_CATALOG = t2.TABLE_CATALOG
AND t1.TABLE_SCHEMA = t2.TABLE_SCHEMA
AND t1.TABLE_NAME = t2.TABLE_NAME
WHERE
t1.TABLE_SCHEMA != 'INFORMATION_SCHEMA'
AND t1.TABLE_CATALOG ILIKE '{DB}'
AND t1.TABLE_SCHEMA IN ({relevant schemas});Example:
SELECT
*,
t1.COMMENT AS COLUMN_COMMENT,
t2.COMMENT AS TABLE_COMMENT
FROM
ACME_DEMO.INFORMATION_SCHEMA.COLUMNS t1
LEFT JOIN ACME_DEMO.INFORMATION_SCHEMA.TABLES t2 ON
t1.TABLE_CATALOG = t2.TABLE_CATALOG
AND t1.TABLE_SCHEMA = t2.TABLE_SCHEMA
AND t1.TABLE_NAME = t2.TABLE_NAME
WHERE
t1.TABLE_SCHEMA != 'INFORMATION_SCHEMA'
AND t1.TABLE_CATALOG ILIKE 'ACME_DEMO'
AND t1.TABLE_SCHEMA IN ('MARTS', 'INTERMEDIATE', 'STAGING', 'RAW');Primary Keys, Foreign Keys, and Unique Constraints
For each database and schema, run these queries:
SHOW PRIMARY KEYS IN SCHEMA {db}.{schema};
SHOW IMPORTED KEYS IN SCHEMA {db}.{schema};Example:
SHOW PRIMARY KEYS IN SCHEMA ACME_DEMO.INTERMEDIATE;
SHOW IMPORTED KEYS IN SCHEMA ACME_DEMO.INTERMEDIATE;Query History Collection
Queries with Database Context
For each database, run:
SELECT
QUERY_ID,
QUERY_TEXT,
DATABASE_NAME,
SCHEMA_NAME,
QUERY_TYPE,
USER_NAME,
ROLE_NAME,
WAREHOUSE_NAME,
EXECUTION_STATUS,
START_TIME,
END_TIME,
TOTAL_ELAPSED_TIME,
QUERY_HASH,
QUERY_PARAMETERIZED_HASH,
USER_TYPE,
USER_DATABASE_NAME,
USER_SCHEMA_NAME,
ROWS_WRITTEN_TO_RESULT
FROM
SNOWFLAKE.ACCOUNT_USAGE.QUERY_HISTORY
WHERE
QUERY_TYPE = 'SELECT'
AND QUERY_TAG != 'SolidData'
AND EXECUTION_STATUS = 'SUCCESS'
AND END_TIME > '{today - 90 days}'
AND DATABASE_NAME ILIKE '{DB}'
AND ROWS_WRITTEN_TO_RESULT > 0
AND SCHEMA_NAME IN ({relevant schemas})
ORDER BY
END_TIME DESC
LIMIT 1000000;Example:
SELECT
QUERY_ID,
QUERY_TEXT,
DATABASE_NAME,
SCHEMA_NAME,
QUERY_TYPE,
USER_NAME,
ROLE_NAME,
WAREHOUSE_NAME,
EXECUTION_STATUS,
START_TIME,
END_TIME,
TOTAL_ELAPSED_TIME,
QUERY_HASH,
QUERY_PARAMETERIZED_HASH,
USER_TYPE,
USER_DATABASE_NAME,
USER_SCHEMA_NAME,
ROWS_WRITTEN_TO_RESULT
FROM
SNOWFLAKE.ACCOUNT_USAGE.QUERY_HISTORY
WHERE
QUERY_TYPE = 'SELECT'
AND QUERY_TAG != 'SolidData'
AND EXECUTION_STATUS = 'SUCCESS'
AND END_TIME > '2025-09-07 18:49:47 +0000'
AND DATABASE_NAME ILIKE 'ACME_DEMO'
AND ROWS_WRITTEN_TO_RESULT > 0
AND SCHEMA_NAME IN ('MARTS', 'INTERMEDIATE', 'STAGING', 'RAW')
ORDER BY
END_TIME DESC
LIMIT 1000000;Queries without Database Context
Run this query to capture queries that don't reference a specific database:
SELECT
QUERY_ID,
QUERY_TEXT,
DATABASE_NAME,
SCHEMA_NAME,
QUERY_TYPE,
USER_NAME,
ROLE_NAME,
WAREHOUSE_NAME,
EXECUTION_STATUS,
START_TIME,
END_TIME,
TOTAL_ELAPSED_TIME,
QUERY_HASH,
QUERY_PARAMETERIZED_HASH,
USER_TYPE,
USER_DATABASE_NAME,
USER_SCHEMA_NAME,
ROWS_WRITTEN_TO_RESULT
FROM
SNOWFLAKE.ACCOUNT_USAGE.QUERY_HISTORY
WHERE
QUERY_TYPE = 'SELECT'
AND EXECUTION_STATUS = 'SUCCESS'
AND END_TIME > '{today - 90 days}'
AND DATABASE_NAME IS NULL
AND ROWS_WRITTEN_TO_RESULT > 0
ORDER BY
END_TIME DESC
LIMIT 1000000;Example:
SELECT
QUERY_ID,
QUERY_TEXT,
DATABASE_NAME,
SCHEMA_NAME,
QUERY_TYPE,
USER_NAME,
ROLE_NAME,
WAREHOUSE_NAME,
EXECUTION_STATUS,
START_TIME,
END_TIME,
TOTAL_ELAPSED_TIME,
QUERY_HASH,
QUERY_PARAMETERIZED_HASH,
USER_TYPE,
USER_DATABASE_NAME,
USER_SCHEMA_NAME,
ROWS_WRITTEN_TO_RESULT
FROM
SNOWFLAKE.ACCOUNT_USAGE.QUERY_HISTORY
WHERE
QUERY_TYPE = 'SELECT'
AND EXECUTION_STATUS = 'SUCCESS'
AND END_TIME > '2025-09-07 18:49:47 +0000'
AND DATABASE_NAME IS NULL
AND ROWS_WRITTEN_TO_RESULT > 0
ORDER BY
END_TIME DESC
LIMIT 1000000;Users Collection
SELECT * FROM SNOWFLAKE.ACCOUNT_USAGE.USERS;Table Usage Collection
For each database, run:
SELECT
DATABASE_NAME,
SCHEMA_NAME,
TABLE_NAME,
DATE(START_TIME) AS DAY,
SUM(ROWS_ADDED) AS total_rows_added,
SUM(ROWS_REMOVED) AS total_rows_removed,
SUM(ROWS_UPDATED) AS total_rows_updated,
(SUM(ROWS_ADDED) + SUM(ROWS_REMOVED) + SUM(ROWS_UPDATED)) AS total_count
FROM
SNOWFLAKE.ACCOUNT_USAGE.TABLE_DML_HISTORY
WHERE
START_TIME >= '{today - 90 days}'
AND END_TIME <= 'today'
AND DATABASE_NAME = '{db}'
AND SCHEMA_NAME IN ({relevant schemas})
GROUP BY
DATABASE_NAME,
SCHEMA_NAME,
TABLE_NAME,
DATE(START_TIME)
HAVING
(SUM(ROWS_ADDED) + SUM(ROWS_REMOVED) + SUM(ROWS_UPDATED)) > 0
ORDER BY
DAY ASC;Example:
SELECT
DATABASE_NAME,
SCHEMA_NAME,
TABLE_NAME,
DATE(START_TIME) AS DAY,
SUM(ROWS_ADDED) AS total_rows_added,
SUM(ROWS_REMOVED) AS total_rows_removed,
SUM(ROWS_UPDATED) AS total_rows_updated,
(SUM(ROWS_ADDED) + SUM(ROWS_REMOVED) + SUM(ROWS_UPDATED)) AS total_count
FROM
SNOWFLAKE.ACCOUNT_USAGE.TABLE_DML_HISTORY
WHERE
START_TIME >= '2025-09-07 00:00:00.000'
AND END_TIME <= '2025-10-12 00:00:00.000'
AND DATABASE_NAME = 'ACME_DEMO'
AND SCHEMA_NAME IN ('MARTS', 'INTERMEDIATE', 'STAGING', 'RAW')
GROUP BY
DATABASE_NAME,
SCHEMA_NAME,
TABLE_NAME,
DATE(START_TIME)
HAVING
(SUM(ROWS_ADDED) + SUM(ROWS_REMOVED) + SUM(ROWS_UPDATED)) > 0
ORDER BY
DAY ASC;What Data Does Solid Collect?
For transparency, here are the specific queries Solid executes when automatically collecting data.
Metadata
SELECT
*,
t1.COMMENT AS COLUMN_COMMENT,
t2.COMMENT AS TABLE_COMMENT
FROM
{database}.INFORMATION_SCHEMA.COLUMNS t1
LEFT JOIN {database}.INFORMATION_SCHEMA.TABLES t2
ON t1.TABLE_CATALOG = t2.TABLE_CATALOG
AND t1.TABLE_SCHEMA = t2.TABLE_SCHEMA
AND t1.TABLE_NAME = t2.TABLE_NAME
WHERE
t1.TABLE_SCHEMA != 'INFORMATION_SCHEMA'
AND t1.TABLE_CATALOG ILIKE '{database}'
AND t1.TABLE_SCHEMA IN ({schemas});Query History
Queries with database context:
SELECT
QUERY_ID, QUERY_TEXT, DATABASE_NAME, SCHEMA_NAME, QUERY_TYPE,
USER_NAME, ROLE_NAME, WAREHOUSE_NAME, EXECUTION_STATUS,
START_TIME, END_TIME, TOTAL_ELAPSED_TIME, QUERY_HASH,
QUERY_PARAMETERIZED_HASH, USER_TYPE, USER_DATABASE_NAME,
USER_SCHEMA_NAME, ROWS_WRITTEN_TO_RESULT
FROM
SNOWFLAKE.ACCOUNT_USAGE.QUERY_HISTORY
WHERE
QUERY_TYPE='SELECT'
AND QUERY_TAG!='SolidData'
AND EXECUTION_STATUS='SUCCESS'
AND END_TIME>'{last_collect_time}'
AND DATABASE_NAME ILIKE '{database}'
AND ROWS_WRITTEN_TO_RESULT > 0
ORDER BY END_TIME DESC
LIMIT 1000000;Queries without database context:
SELECT
QUERY_ID, QUERY_TEXT, DATABASE_NAME, SCHEMA_NAME, QUERY_TYPE,
USER_NAME, ROLE_NAME, WAREHOUSE_NAME, EXECUTION_STATUS,
START_TIME, END_TIME, TOTAL_ELAPSED_TIME, QUERY_HASH,
QUERY_PARAMETERIZED_HASH, USER_TYPE, USER_DATABASE_NAME,
USER_SCHEMA_NAME, ROWS_WRITTEN_TO_RESULT
FROM
SNOWFLAKE.ACCOUNT_USAGE.QUERY_HISTORY
WHERE
QUERY_TYPE='SELECT'
AND EXECUTION_STATUS='SUCCESS'
AND END_TIME>'{last_collect_time}'
AND DATABASE_NAME IS NULL
AND ROWS_WRITTEN_TO_RESULT > 0
ORDER BY END_TIME DESC
LIMIT 1000000;Table Usage
SELECT
DATABASE_NAME, SCHEMA_NAME, TABLE_NAME,
DATE(START_TIME) AS day,
SUM(ROWS_ADDED) AS total_rows_added,
SUM(ROWS_REMOVED) AS total_rows_removed,
SUM(ROWS_UPDATED) AS total_rows_updated,
(SUM(ROWS_ADDED) + SUM(ROWS_REMOVED) + SUM(ROWS_UPDATED)) AS total_count
FROM
SNOWFLAKE.ACCOUNT_USAGE.TABLE_DML_HISTORY
WHERE
START_TIME >= '{start_day}'
AND END_TIME <= '{end_day}'
AND DATABASE_NAME = '{database}'
GROUP BY DATABASE_NAME, SCHEMA_NAME, TABLE_NAME, DATE(START_TIME)
HAVING (SUM(ROWS_ADDED) + SUM(ROWS_REMOVED) + SUM(ROWS_UPDATED)) > 0
ORDER BY day ASC;Primary and Foreign Keys
SHOW PRIMARY KEYS IN SCHEMA {database}.{schema};
SHOW IMPORTED KEYS IN SCHEMA {database}.{schema};Users
SELECT * FROM SNOWFLAKE.ACCOUNT_USAGE.USERS;Column Data Profiling (Optional — Requires Read Access)
This only applies if you enabled Section 6 (Read-Only Grants) in the setup script.
Solid samples up to 100,000 rows per table to profile your data:
| Column Type | Metrics Collected |
|---|---|
| Numeric | MIN, MAX, AVG, row count, distinct count, null count |
| Text | Top 100 distinct values (LISTAGG), row count, distinct count, null count |
| Date | MIN and MAX values, row count, distinct count, null count |
Connecting in Solid
Step 1: Navigate to Integrations
Go to Settings → Integrations → Snowflake
Step 2: Enter Connection Details
| Field | What to Enter |
|---|---|
| User | SOLID_DATA (or your service user name) |
| Password / Private Key | Your authentication credential |
| Account | Your Snowflake account identifier |
| Warehouse | SOLID_DATA_WH (or your warehouse name) |
Step 3: Test the Connection
Click Test Connection. If it fails:
- Double-check your credentials
- Make sure the warehouse is running
- Confirm the role has USAGE rights on the database
Step 4: Select What to Monitor
Choose which databases and schemas you want Solid to analyze.
Step 5: Save
Click Save and Solid will start analyzing your data.
Troubleshooting
Connection Issues
- Verify you replaced
<your_database>with your actual database name in the script - Confirm you have ACCOUNTADMIN role when running the setup script
- Check the warehouse is running in Snowflake
- Verify all grants completed successfully by reviewing the script output
Permission Issues
- Check the role permissions by running
SHOW GRANTS TO ROLE SOLID_DATA_ROLE; - Verify the database name matches what you specified in the setup
- Ensure future grants are in place for new tables and views
Performance Concerns
The Solid warehouse uses XSMALL size and auto-suspends after 5 minutes of inactivity. You can adjust these settings by modifying the warehouse configuration in the setup script.
Security Notes
- The service user created has read-only access to metadata and query history
- Optional data profiling requires explicit SELECT grants (Section 6)
- All credentials should be stored securely
- The service user does not have permissions to modify data or schema
- The REFERENCES privilege allows foreign key constraints and metadata lookups but does not allow data access
Updated 14 days ago
