Snowflake's QUERY_HISTORY exposes detailed execution statistics for every query, making it essential for performance analysis, bottleneck identification, and cost optimization. There are two ways to retrieve it — the INFORMATION_SCHEMA table function and the ACCOUNT_USAGE view — and they differ in latency, retention, and permission model.
QUERY_HISTORY has two retrieval points. The exam asks about the differences precisely, so make sure the comparison below is locked in.
| Dimension | INFORMATION_SCHEMA.QUERY_HISTORY() | ACCOUNT_USAGE.QUERY_HISTORY |
|---|---|---|
| Type | Table function | View |
| Retention | Last 7 days | 365 days |
| Data latency | None (real-time) | Up to 45 minutes |
| Max rows | 10,000 (RESULT_LIMIT) | No limit |
| Scope | Queries visible to the current role | Every query in the account |
| Required privilege | None special (within role scope) | IMPORTED PRIVILEGES on the SNOWFLAKE DB |
| How to call | SELECT * FROM TABLE(INFORMATION_SCHEMA.QUERY_HISTORY(...)) | SELECT * FROM SNOWFLAKE.ACCOUNT_USAGE.QUERY_HISTORY |
Call it as a table function and filter by time range or user with named parameters.
-- Query history from the last hour
SELECT *
FROM TABLE(INFORMATION_SCHEMA.QUERY_HISTORY(
DATE_RANGE_START => DATEADD('HOUR', -1, CURRENT_TIMESTAMP()),
DATE_RANGE_END => CURRENT_TIMESTAMP(),
RESULT_LIMIT => 100
))
ORDER BY START_TIME DESC;
-- Query history for a specific user
SELECT
QUERY_ID,
QUERY_TEXT,
TOTAL_ELAPSED_TIME,
BYTES_SCANNED,
ROWS_PRODUCED,
WAREHOUSE_NAME
FROM TABLE(INFORMATION_SCHEMA.QUERY_HISTORY_BY_USER(
USER_NAME => 'ANALYST_USER',
RESULT_LIMIT => 50
))
ORDER BY TOTAL_ELAPSED_TIME DESC;
-- Query history for a specific warehouse
SELECT *
FROM TABLE(INFORMATION_SCHEMA.QUERY_HISTORY_BY_WAREHOUSE(
WAREHOUSE_NAME => 'ANALYTICS_WH',
RESULT_LIMIT => 50
));Use the ACCOUNT_USAGE view for long-range analysis or an account-wide overview. Remember the up-to-45-minute delay and reach for INFORMATION_SCHEMA when you need real-time monitoring.
-- 30-day query summary
SELECT
USER_NAME,
WAREHOUSE_NAME,
COUNT(*) AS query_count,
AVG(TOTAL_ELAPSED_TIME) / 1000 AS avg_elapsed_sec,
SUM(BYTES_SCANNED) / POWER(1024, 3) AS total_scanned_tb,
AVG(PARTITIONS_SCANNED / NULLIF(PARTITIONS_TOTAL, 0)) AS avg_scan_ratio
FROM SNOWFLAKE.ACCOUNT_USAGE.QUERY_HISTORY
WHERE START_TIME >= DATEADD('DAY', -30, CURRENT_TIMESTAMP())
AND EXECUTION_STATUS = 'SUCCESS'
GROUP BY USER_NAME, WAREHOUSE_NAME
ORDER BY total_scanned_tb DESC;Three angles to triage performance bottlenecks:
-- Top 20 longest-running queries in the last 7 days
SELECT
QUERY_ID,
SUBSTR(QUERY_TEXT, 1, 200) AS query_preview,
USER_NAME,
WAREHOUSE_NAME,
WAREHOUSE_SIZE,
TOTAL_ELAPSED_TIME / 1000 AS elapsed_sec,
COMPILATION_TIME / 1000 AS compile_sec,
EXECUTION_TIME / 1000 AS exec_sec,
QUEUED_OVERLOAD_TIME / 1000 AS queue_sec,
BYTES_SCANNED / POWER(1024, 3) AS scanned_tb
FROM SNOWFLAKE.ACCOUNT_USAGE.QUERY_HISTORY
WHERE START_TIME >= DATEADD('DAY', -7, CURRENT_TIMESTAMP())
AND EXECUTION_STATUS = 'SUCCESS'
AND QUERY_TYPE = 'SELECT'
ORDER BY TOTAL_ELAPSED_TIME DESC
LIMIT 20;-- Queries with pruning under 50% (scanning more than 50% of partitions)
SELECT
QUERY_ID,
SUBSTR(QUERY_TEXT, 1, 200) AS query_preview,
PARTITIONS_SCANNED,
PARTITIONS_TOTAL,
ROUND(PARTITIONS_SCANNED / NULLIF(PARTITIONS_TOTAL, 0) * 100, 1) AS scan_pct,
BYTES_SCANNED / POWER(1024, 2) AS scanned_mb
FROM SNOWFLAKE.ACCOUNT_USAGE.QUERY_HISTORY
WHERE START_TIME >= DATEADD('DAY', -7, CURRENT_TIMESTAMP())
AND PARTITIONS_TOTAL > 100
AND PARTITIONS_SCANNED / NULLIF(PARTITIONS_TOTAL, 0) > 0.5
AND EXECUTION_STATUS = 'SUCCESS'
ORDER BY scan_pct DESC
LIMIT 20;-- Queries with more than 5 seconds in the queue (a sign of warehouse shortage)
SELECT
QUERY_ID,
WAREHOUSE_NAME,
QUEUED_OVERLOAD_TIME / 1000 AS queue_sec,
QUEUED_PROVISIONING_TIME / 1000 AS provisioning_sec,
TOTAL_ELAPSED_TIME / 1000 AS elapsed_sec,
START_TIME
FROM SNOWFLAKE.ACCOUNT_USAGE.QUERY_HISTORY
WHERE START_TIME >= DATEADD('DAY', -7, CURRENT_TIMESTAMP())
AND QUEUED_OVERLOAD_TIME > 5000
ORDER BY QUEUED_OVERLOAD_TIME DESC
LIMIT 20;| Column | Meaning | How to use it |
|---|---|---|
| TOTAL_ELAPSED_TIME | Total query execution time (ms) | Find queries with the largest cost impact |
| COMPILATION_TIME | Compilation time (ms) | Identify complex queries to optimize |
| QUEUED_OVERLOAD_TIME | Time waiting in the warehouse queue (ms) | Detect undersized warehouses |
| BYTES_SCANNED | Volume of data scanned | Detect full table scans |
| PARTITIONS_SCANNED / TOTAL | Scanned vs. total partitions | Evaluate pruning efficiency |
| BYTES_SPILLED_TO_LOCAL_STORAGE | Spill to local disk | Detect memory pressure |
| BYTES_SPILLED_TO_REMOTE_STORAGE | Spill to remote storage | Detect severe memory pressure |
SnowPro
Question 1
An account administrator wants to analyze query execution statistics for all users over the last 90 days. Which data source is most appropriate?
Correct answer: B
INFORMATION_SCHEMA.QUERY_HISTORY() only covers the last 7 days and caps at 10,000 rows, so it doesn't fit a 90-day analysis. ACCOUNT_USAGE.QUERY_HISTORY retains 365 days of account-wide history, which matches the requirement. Just remember that the data lags by up to 45 minutes.
What is the difference between INFORMATION_SCHEMA.QUERY_HISTORY and ACCOUNT_USAGE.QUERY_HISTORY?
INFORMATION_SCHEMA.QUERY_HISTORY() is a table function that returns up to 10,000 rows of the last 7 days of query history with no delay. It only shows queries the current role has permission to see. ACCOUNT_USAGE.QUERY_HISTORY is a view that retains up to 365 days of account-wide history, but data is delayed by up to 45 minutes. Reading it requires IMPORTED PRIVILEGES on the SNOWFLAKE database.
Which columns identify the most expensive queries in QUERY_HISTORY?
There is no direct cost column, but you combine three metrics to find bottlenecks: TOTAL_ELAPSED_TIME (execution time in ms), BYTES_SCANNED (volume of data scanned), and PARTITIONS_SCANNED / PARTITIONS_TOTAL (pruning efficiency). Warehouse credits are billed by time, so queries with longer TOTAL_ELAPSED_TIME have the largest cost impact.
How do I retain QUERY_HISTORY data for longer than 365 days?
ACCOUNT_USAGE.QUERY_HISTORY only keeps 365 days of data. To retain it longer, create a task that periodically copies rows into a dedicated table with CREATE TABLE AS SELECT or INSERT INTO. A common pattern is a daily Serverless Task that incrementally copies the previous day's rows.
Practice with certification-focused question sets
Try free questionsNicheeLab Editorial Team
NicheeLab editorial team focused on data engineering and cloud certification learning. Content is structured around practical study needs and official exam domains.
Snowflake Certifications: All 11 Exams Explained (2026)
Every SnowPro certification — Associate, Core, Specialty, Ad...
Snowflake Exam Difficulty Ranking: All 11 Certs Compared (2026)
All 11 SnowPro exams ranked by difficulty with study-time es...
Snowflake Study Guide: Fastest Pass Route by Exam (2026)
How to pass SnowPro certifications efficiently — official ma...
SnowPro Core (COF-C03): Complete Exam Guide (2026)
Pass the SnowPro Core exam — six domains, scope, sample ques...
SnowPro Associate Platform (SOL-C01): Complete Guide (2026)
The entry-level SnowPro Associate exam — scope, weighting, s...