What you will be able to do
- Inspect running transactions and held locks with SHOW TRANSACTIONS, SHOW LOCKS, DESCRIBE TRANSACTION and CURRENT_TRANSACTION
- Trace a blocked query back to its blocker transaction with QUERY_HISTORY and LOCK_WAIT_HISTORY
- Abort a detached or blocking transaction, and know when Snowflake aborts one automatically
- Tell lock-wait timeouts apart from statement-runtime timeouts and query cancellation
1.Seeing what is running and what is locked right now
When a writer is stuck, start by looking at what is running now. Snowflake gives you two SHOW commands for this, and neither needs a running warehouse.
SHOW TRANSACTIONS lists running transactions with their id, user, session, name, started_on, state and scope. The scope column is 0 for an ordinary transaction. For a scoped transaction it holds an ID, which tells you whether two transactions are in the same scope; this happens when a stored procedure with a transaction is called from inside another transaction. SHOW LOCKS lists running transactions that hold locks. By default, both commands show only the current user's sessions. Add IN ACCOUNT to see every user. For SHOW TRANSACTIONS that option requires ACCOUNTADMIN; for SHOW LOCKS, other roles still see only their own locks. Both commands return at most ten thousand records. You can post-process their output with RESULT_SCAN or the ->> pipe operator, putting the lowercase column names in double quotes.
| Column | What it tells you |
|---|---|
| resource | Fully qualified table name, or a transaction ID |
| type | PARTITIONS for standard tables, ROW for hybrid tables |
| transaction | Transaction ID, which you can pass to SYSTEM$ABORT_TRANSACTION |
| status | HOLDING or WAITING |
| acquired_on | When the lock was acquired |
| session | Session ID, visible only to ACCOUNTADMIN |
Every transaction has a unique ID, a signed 64-bit integer. Inside a session, CURRENT_TRANSACTION returns the ID of the transaction that is running there. If you already have an ID, DESCRIBE TRANSACTION shows its details while it is still running or after it has committed or aborted. The output includes a state column and an ended_on column. Other context functions that help here are CURRENT_STATEMENT, LAST_QUERY_ID and LAST_TRANSACTION.
DESCRIBE TRANSACTION 1721161383427000000;Checkpoint 1 of 6· Match them up
Match each command or function to what it gives you
Tap a term, then the definition that fits it.
The two SHOW commands list what is active now. DESCRIBE TRANSACTION looks up one known ID, even after it ends. CURRENT_TRANSACTION returns your own session's ID.
“while it is still running or after it has committed or aborted”Source: docs.snowflake.com
2.Finding the blocker after the fact with LOCK_WAIT_HISTORY
SHOW LOCKS only shows the present. To investigate last night's waiting, use two Account Usage views together. In QUERY_HISTORY, the TRANSACTION_BLOCKED_TIME column shows how long each query waited for a lock. LOCK_WAIT_HISTORY records the lock waits themselves. Each row is one transaction waiting on a lock, with its QUERY_ID, TRANSACTION_ID, the LOCK_TYPE (PARTITION, STREAM, TABLE or ROW), REQUESTED_AT, ACQUIRED_AT, and a BLOCKER_QUERIES JSON array of up to 20 blockers. A blocker with is_snowflake set to TRUE is a Snowflake background process, such as automatic maintenance of materialized views. Other transactions may be queued ahead of the one in a given row for the same lock.
SELECT query_id, query_text, start_time, session_id, execution_status, total_elapsed_time, compilation_time, execution_time, transaction_blocked_time FROM snowflake.account_usage.query_history WHERE start_time >= dateadd('hours', -24, current_timestamp()) AND transaction_blocked_time > 0 ORDER BY transaction_blocked_time DESC;Next, look up those query IDs in LOCK_WAIT_HISTORY and note the transaction_id of each entry in blocker_queries. Then query QUERY_HISTORY by each of those transaction IDs to see every statement in the blocker transaction. Look at all of them. The first blocker query is the statement that was running when the wait began, but an earlier DML statement in that transaction may already have taken the lock. A later run of the same jobs may block on a different statement in the same transaction.
Which statements can block each other? UPDATE, DELETE and MERGE statements hold locks that generally prevent them from running in parallel with other UPDATE, DELETE and MERGE statements. Most INSERT and COPY statements write only new partitions, so they often can run in parallel with other INSERT and COPY operations, and sometimes can run in parallel with an UPDATE, DELETE or MERGE statement. This is why concurrent loads usually do not appear as blockers of each other.
Checkpoint 2 of 6· Put it in order
Put the documented blocked-transaction investigation in order
- 1.Query LOCK_WAIT_HISTORY for those query IDs and note the blocker transaction_id values
- 2.Query QUERY_HISTORY by each blocker transaction_id
- 3.Review every statement in the blocker transaction for DML on the locked resource
- 4.Query QUERY_HISTORY for queries with TRANSACTION_BLOCKED_TIME > 0 and note their query IDs
The procedure starts from blocked time, uses LOCK_WAIT_HISTORY to find the blockers, then reads every statement in each blocker transaction.
“Review the results of the query and note the query IDs of the queries with high TRANSACTION_BLOCKED_TIME values.”Source: docs.snowflake.com
Checkpoint 3 of 6· Fill the gap
Which column filters this query to blocked transactions whose lock request was made in the past 24 hours?
SELECT query_id, object_name, transaction_id, blocker_queries
FROM SNOWFLAKE.ACCOUNT_USAGE.LOCK_WAIT_HISTORY
WHERE ? >= DATEADD('hours', -24, CURRENT_TIMESTAMP());REQUESTED_AT is when the waiting transaction asked for the lock. ACQUIRED_AT is when the lock was obtained, and start_time and transaction_blocked_time are QUERY_HISTORY columns.
Source: docs.snowflake.comCheckpoint 4 of 6· Exam question
A data engineer wants to avoid table-lock waits and proposes a queue that serializes six COPY INTO loads (different staged files) into one standard table so only one runs at a time. As the administrator, which response is MOST appropriate?
Correct answer: D — Drop the serialization, because INSERT and COPY statements usually run in parallel with each other and need not wait.
- A. Incorrect: COPY does not take a table lock that blocks other loads; the exclusive-style blocking applies to UPDATE, DELETE and MERGE.
- B. Incorrect: there is no per-partition-range limit on concurrent COPY into a standard table, and moving to staging tables only adds extra steps.
- C. Incorrect: explicit transactions are not required for concurrency; statements in autocommit mode run in parallel when their lock behavior allows it.
- D. Correct: INSERT and COPY append new micro-partitions and often run in parallel with each other, so serializing them adds latency without benefit.
3.Aborting transactions, automatic aborts and timeouts
Once you have the blocker's ID from SHOW TRANSACTIONS or SHOW LOCKS, you can end it with SYSTEM$ABORT_TRANSACTION. The user who started the transaction can do this, and so can an account administrator. The function works only on explicit, multi-statement transactions. For an autocommit transaction, abort the associated job instead. Calling it on a transaction that has already committed or rolled back changes nothing. If a DDL statement has already committed the open transaction implicitly, that transaction can no longer be aborted.
The typical case is a session that disconnects abruptly. Its transaction is left detached and keeps its locks. If nobody aborts it, Snowflake does so automatically under the rules below.
| Condition | Automatic abort after |
|---|---|
| It blocks another transaction from locking the same table and is idle | 5 minutes idle |
| It does not block other transactions from modifying the same table | Older than 4 hours |
| It reads from or writes to hybrid tables and is idle, blocking or not | 5 minutes idle |
SELECT SYSTEM$ABORT_TRANSACTION(1442254688149);Cancelling a query is a different action. Snowflake recommends cancelling through the client's interface or the JDBC/ODBC cancellation API. In SQL, SYSTEM$CANCEL_QUERY cancels a single query, and SYSTEM$CANCEL_ALL_QUERIES cancels every active query in one session. To cancel by warehouse or by user, use ALTER WAREHOUSE … ABORT ALL QUERIES or ALTER USER … ABORT ALL QUERIES.
Don't confuse the two kinds of timeout. LOCK_TIMEOUT limits how long a statement waits for a lock. STATEMENT_TIMEOUT_IN_SECONDS limits how long a running statement may run before the system cancels it. You can set it on the account, user or session, and also on a warehouse. When it is set in both the session hierarchy and the warehouse, the lower non-zero value applies.
Checkpoint 5 of 6· Check yourself
A client crashed in the middle of an explicit transaction that updated ORDERS. Other jobs are now waiting on ORDERS. What is the most direct documented fix?
A detached transaction still holds its locks, and SYSTEM$ABORT_TRANSACTION ends it by ID. Cancelling queries does not end the transaction. The 4-hour rule is for transactions that are not blocking anyone; a blocking one is aborted after 5 idle minutes.
“the transaction is left in a detached state, including any locks that the transaction is holding on resources”Source: docs.snowflake.com
Checkpoint 6 of 6· Exam question
A latency-sensitive API runs single-row UPDATE statements against a standard table that a nightly batch frequently locks for hours. The API must return an error within 60 seconds instead of waiting. Which configuration should the administrator apply to the API's sessions?
Correct answer: B — Run ALTER SESSION SET LOCK_TIMEOUT = 60 so blocked statements give up after one minute of waiting for the lock.
- A. Incorrect: STATEMENT_QUEUED_TIMEOUT_IN_SECONDS limits time spent queued for warehouse compute, not time spent waiting on a table lock.
- B. Correct: LOCK_TIMEOUT sets how long a statement waits for a lock before failing; its default is 43200 seconds, so 60 gives the required fail-fast behavior.
- C. Incorrect: a one-hour statement timeout does not match the 60-second requirement and also cancels legitimately long-running work, not just lock waits.
- D. Incorrect: TRANSACTION_ABORT_ON_ERROR controls whether a failed statement aborts the surrounding transaction; it does not shorten lock waits.
Exam traps
Each one states something that sounds right. Open it to see what is actually true.
1.The first entry in BLOCKER_QUERIES is the statement that took the lock, so it is the only one to investigate.Why is that wrong?
The first entry is just the statement that was running when the wait began. Earlier or later DML in the same blocker transaction may hold the lock.
Covered in Finding the blocker after the fact with LOCK_WAIT_HISTORY
2.SYSTEM$ABORT_TRANSACTION can stop any long-running autocommit DML statement.Why is that wrong?
The function works only on explicit, multi-statement transactions. To stop an autocommit transaction, abort its job.
Covered in Aborting transactions, automatic aborts and timeouts
Practise it for real
Create a lock in one session, watch it from another, then release it with SYSTEM$ABORT_TRANSACTION.
1.In session A, run BEGIN TRANSACTION, then an UPDATE on a scratch table, then SELECT CURRENT_TRANSACTION(); and do not commit.
Why: An open explicit transaction keeps its lock until COMMIT or ROLLBACK.
You should see: A 64-bit transaction ID is returned.
2.In session B, logged in as the same user as session A, run SHOW TRANSACTIONS; and then SHOW LOCKS;
Why: These list the running transactions and the locks they hold for the current user across all of that user's sessions. Use IN ACCOUNT as ACCOUNTADMIN to see other users.
You should see: Session A's transaction appears, and SHOW LOCKS shows the table with type PARTITIONS and status HOLDING.
3.In session B, run an UPDATE on the same table. From a third session of the same user, run SHOW LOCKS; again.
Why: Locks block other statements from modifying the resource until they are released, so the second UPDATE has to wait for session A's lock.
You should see: Session B's UPDATE does not complete, and session A's transaction still shows HOLDING.
4.Run SELECT SYSTEM$ABORT_TRANSACTION(<id from step 1>); and then DESCRIBE TRANSACTION <id>;
Why: Aborting releases the lock. DESCRIBE TRANSACTION still works after a transaction ends.
You should see: An 'Aborted transaction id' message. Session B's UPDATE then proceeds, and DESCRIBE shows a state that is no longer running.
Stuck? Get a nudge
If session B's UPDATE fails at once instead of waiting, check whether LOCK_TIMEOUT is set to 0 for that session.
Sources
Every claim above is drawn from one of these pages, quoted as it was written on the date shown.
- 1.
“It can only be used by users with the ACCOUNTADMIN role (i.e. account administrators).”
↩︎ Seeing what is running and what is locked right now - 2.
“Returns all locks across all users in the account. This parameter only applies when executed by users with the ACCOUNTADMIN role”
↩︎ Seeing what is running and what is locked right now“Current status of the transaction: HOLDING or WAITING.”
↩︎ Seeing what is running and what is locked right now - 3.
“Each row in the output represents a transaction waiting on a lock.”
↩︎ Finding the blocker after the fact with LOCK_WAIT_HISTORY“TRUE if the query is a background process run by Snowflake (e.g., automatic maintenance of materialized views).”
↩︎ Finding the blocker after the fact with LOCK_WAIT_HISTORY - 4.
“Most INSERT and COPY statements write only new partitions.”
↩︎ Finding the blocker after the fact with LOCK_WAIT_HISTORY“UPDATE, DELETE, and MERGE statements hold locks that generally prevent them from running in parallel with other UPDATE, DELETE, and MERGE statements.”
↩︎ Finding the blocker after the fact with LOCK_WAIT_HISTORY“blocks another transaction from acquiring a lock on the same table and is idle for 5 minutes”
↩︎ Aborting transactions, automatic aborts and timeouts“You can set the length of time (in seconds) that a statement should block by setting the LOCK_TIMEOUT parameter.”
↩︎ Aborting transactions, automatic aborts and timeouts“Therefore, you must investigate all queries in the first blocker transaction.”
↩︎ Exam trap 1“while it is still running or after it has committed or aborted”
↩︎ Checkpoint“Review the results of the query and note the query IDs of the queries with high TRANSACTION_BLOCKED_TIME values.”
↩︎ Checkpoint“the transaction is left in a detached state, including any locks that the transaction is holding on resources”
↩︎ Checkpoint - 5.
“Transactions can be aborted only by the user who started the transaction or an account administrator.”
↩︎ Aborting transactions, automatic aborts and timeouts“This function is supported for explicit/multi-statement transactions only. Autocommit transactions can be aborted by aborting the associated job.”
↩︎ Exam trap 2 - 6.
“The recommended way to cancel a statement is to use the interface of the application in which the query is running”
↩︎ Aborting transactions, automatic aborts and timeouts - 7.
“This function is not intended for canceling queries for a particular warehouse or user.”
↩︎ Aborting transactions, automatic aborts and timeouts - 8.
“Amount of time, in seconds, after which a running SQL statement (query, DDL, DML, and so on) is canceled by the system.”
↩︎ Aborting transactions, automatic aborts and timeouts“the timeout is the lowest non-zero value of the two parameters.”
↩︎ Aborting transactions, automatic aborts and timeouts