How to Track Query and User Activity After Migrating from Teradata to Snowflake
By Roland Wenzlofsky · DWHPro
🎯 Why This Matters
In Teradata, QUERY_BAND has long been a hidden gem — the ability to tag every query or session with metadata like App, Job, or UserGroup.
That little string became the key to workload analytics, usage attribution, and auditing.
When moving to Snowflake, you’ll naturally ask:
“Where is my QueryBand?”
Snowflake’s answer is QUERY_TAG, a cleaner, modern mechanism that integrates directly into its metadata views (ACCOUNT_USAGE.QUERY_HISTORY).
This article explains exactly how to reproduce your Teradata tracking patterns — same logic, new syntax.
🧩 Teradata Recap: QUERY_BAND
Example
SET QUERY_BAND='App=Finance;Job=ReportX;UserGroup=Analytics' FOR SESSION;Every query inherits those key/value pairs.
They appear in the DBQL logs and can be joined with resource metrics (CPU, I/O, Spool).
Typical use-cases
- Tag jobs to track their workload footprint
- Separate usage between teams or environments
Limitations
- Requires manual parsing from DBQL tables
- No native cost integration — you must compute it yourself
- Relies on discipline (developers need to set it consistently)
❄️ Snowflake Equivalent: QUERY_TAG
In Snowflake, tagging happens through the QUERY_TAG session parameter.
Every query you run afterward carries that tag into ACCOUNT_USAGE.QUERY_HISTORY.
🧠 Set a tag for your session
ALTER SESSION SET QUERY_TAG = '{"App":"FinanceDashboard",
"Job":"MonthlySummary",
"UserGroup":"Reports"}'All subsequent queries inherit this tag until you clear it:
ALTER SESSION UNSET QUERY_TAG;
It’s exactly the same idea as Teradata’s SET QUERY_BAND = NULL FOR SESSION.
⚙️ Default tags per user or account
You can define permanent defaults (similar to user profile QueryBands):
-- Account-wide default (requires ACCOUNTADMIN)
ALTER ACCOUNT SET QUERY_TAG = 'DefaultTagForThisAccount';
-- Per-user default
ALTER USER DWHPRO SET QUERY_TAG = '{"App":"ETL","UserGroup":"Ops"}';
Lower-level settings (session or user) override higher-level ones.
💻 Set it from your scripts
Wherever your ETL or application code connects to Snowflake, run this at session start:
ALTER SESSION SET QUERY_TAG = '{"App":"ETL","Job":"Load1","Step":"1"}';
📊 Analyzing Queries by Tag
Once tags are being set, you can use Snowflake’s metadata views to measure workload volume, duration, and user behavior.
✅ Works in every account
SELECT
COALESCE(query_tag, '<<NO TAG>>') AS query_tag,
COUNT(*) AS num_queries
FROM SNOWFLAKE.ACCOUNT_USAGE.QUERY_HISTORY
GROUP BY 1
ORDER BY num_queries DESC;
This shows how often each tag was used — similar to counting in Teradata QueryBands in DBQL.
⏱️ Top tags by total runtime
SELECT
query_tag,
COUNT(*) AS num_queries,
SUM(total_elapsed_time) AS total_time_ms,
AVG(total_elapsed_time) AS avg_time_ms
FROM SNOWFLAKE.ACCOUNT_USAGE.QUERY_HISTORY
WHERE query_tag IS NOT NULL
GROUP BY query_tag
ORDER BY total_time_ms DESC;
Equivalent to “total CPU time per QueryBand” in Teradata,but using Snowflake’s elapsed time metric.
🚨 Detect untagged queries
SELECT
user_name,
warehouse_name,
COUNT(*) AS num_untagged,
MAX(start_time) AS last_seen
FROM SNOWFLAKE.ACCOUNT_USAGE.QUERY_HISTORY
WHERE query_tag IS NULL
GROUP BY user_name, warehouse_name
ORDER BY num_untagged DESC;
A simple hygiene check — who’s forgetting to tag?
🕓 Activity in the last 24 hours
SELECT
query_tag,
COUNT(*) AS num_queries,
SUM(total_elapsed_time) AS total_time_ms
FROM SNOWFLAKE.ACCOUNT_USAGE.QUERY_HISTORY
WHERE start_time >= DATEADD(hour, -24, CURRENT_TIMESTAMP())
AND query_tag IS NOT NULL
GROUP BY query_tag
ORDER BY num_queries DESC;
👥 Top users within a tag
SELECT
query_tag,
user_name,
COUNT(*) AS num_queries,
SUM(total_elapsed_time) AS total_time_ms
FROM SNOWFLAKE.ACCOUNT_USAGE.QUERY_HISTORY
WHERE query_tag ILIKE '%"Job":"Load1"%'
GROUP BY query_tag, user_name
ORDER BY num_queries DESC;
Perfect for seeing which users contribute most to a specific workload tag.
💰 Optional: Warehouse-level cost context
Even if per-query credit attribution isn’t available in your region yet, you can still monitor overall warehouse usage:
SELECT
warehouse_name,
start_time::date AS day,
SUM(credits_used) AS credits
FROM SNOWFLAKE.ACCOUNT_USAGE.WAREHOUSE_METERING_HISTORY
GROUP BY warehouse_name, day
ORDER BY day DESC, credits DESC;
Then correlate that with your tagged activity windows.
🔍 Teradata vs Snowflake Quick Comparison
Capability | Teradata ( QUERY_BAND) | Snowflake ( QUERY_TAG) |
Tag type | Arbitrary name/value string | Free-form text or JSON |
Scope | Session / Transaction | Account / User / Session |
Where stored | DBQL log tables | ACCOUNT_USAGE.QUERY_HISTORY |
Cost metrics | Manual from logs | Integrated via usage views |
Discipline needed | High | Still high — same principle |
🚀 Migration Guidelines
- Map existing keys
- Set the tag early
- Audit tagging coverage
- Rebuild your dashboards
Keep your familiar structure: App, Job, UserGroup, Env.
Always run ALTER SESSION SET QUERY_TAG=… right after connecting.
Use the “untagged queries” report regularly.
Replace DBQL with ACCOUNT_USAGE.QUERY_HISTORY.
Focus on query count, elapsed time, and credits.
✅ Takeaway
If you’ve relied on QUERY_BAND for years, you don’t lose that capability when you migrate to Snowflake — you actually simplify it.
ALTER SESSION SET QUERY_TAG='…'
is your new SET QUERY_BAND.
Everything else — analysis, governance — builds naturally on top of ACCOUNT_USAGE.QUERY_HISTORY.
It’s familiar, lightweight, and cloud-native.
🔄 Migration Cheat Sheet
Teradata | Snowflake |
SET QUERY_BAND='App=…;Job=…' FOR SESSION; | ALTER SESSION SET QUERY_TAG='{"App":"…","Job":"…"}'; |
Stored in DBQL | Stored in ACCOUNT_USAGE.QUERY_HISTORY |
Analyze CPU/I/O by band | Analyze elapsed time or credits by tag |
Manual cost mapping | Native warehouse usage views |
✳️ Summary
You can carry your entire QueryBand methodology into Snowflake with almost no conceptual change — just a new command and a richer set of metadata views.
It’s the cleanest one-to-one migration feature you’ll encounter.
