Worth 21% of the SnowPro Core exam.
Verified against the official Snowflake COF-C03 Exam Study Guide — follows guide sections 4.1-4.4. Streams/Tasks/Dynamic Tables moved to Domain 3 to match the official guide's own filing (they're under "automated data ingestion" there, not performance).
SNOWFLAKE.ACCOUNT_USAGE views: QUERY_HISTORY (execution details, retained longer than
INFORMATION_SCHEMA's version) and query attribution views (which warehouse/user/query tag
drove which cost) — the go-to source for retrospective performance/cost analysis.INSERT/COPY/UPDATE/DELETE). Requires enough partitions to be worth splitting and no
nondeterministic functions (RANDOM(), SEQ) in the query."ineligible", "ineligibleReason": "NO_LARGE_ENOUGH_SCAN" from
SYSTEM$ESTIMATE_QUERY_ACCELERATION(). A selective filter over a genuinely large (many
GB-TB) production table is the real target, not GB-scale data regardless of selectivity.QUERY_ACCELERATION_MAX_SCALE_FACTOR: a hard cost multiplier on the warehouse's own
rate, not a performance dial — e.g. a Medium warehouse (4 credits/hr) with scale factor 5 can
lease up to 20 additional credits/hr of QAS compute. 0 = no upper bound. Billed separately
from warehouse credits, serverless, per-second, only while in use. Default scale factor
(verified against current docs): 8 when QAS is explicitly enabled by hand, but only 2
when it's auto-enabled (Gen2/multi-cluster warehouses can auto-enable QAS) — worth knowing the
auto-enabled default is deliberately more conservative than the manual one.SYSTEM$ESTIMATE_QUERY_ACCELERATION (query_id). Check what actually happened after: QUERY_ACCELERATION_BYTES_SCANNED /
_PARTITIONS_SCANNED / _UPPER_LIMIT_SCALE_FACTOR columns in QUERY_HISTORY. Two more
monitoring surfaces worth knowing by name: the QUERY_ACCELERATION_ELIGIBLE view
(identifies which queries/warehouses would benefit most from turning QAS on) and the
QUERY_ACCELERATION_HISTORY view/table function (historical QAS billing/usage, separate
from ordinary warehouse credit consumption).IN/LIKE (verified
against current docs) — it also covers: substring and regex matches (LIKE/ILIKE/RLIKE),
NULL checks, geospatial predicates on GEOGRAPHY values, full-text search via the
SEARCH/SEARCH_IP functions, and lookups into semi-structured VARIANT/OBJECT/ARRAY
columns — not just simple scalar-column equality.
ALTER TABLE <table> ADD SEARCH OPTIMIZATION; — builds a specialized access path
asynchronously in the background, not instantly; check search_optimization_progress in
SHOW TABLES output (0-100) to see build status, and search_optimization_bytes for the
access path's storage footprint once built.SYSTEM$ESTIMATE_QUERY_ACCELERATION's sibling function,
SYSTEM$ESTIMATE_SEARCH_OPTIMIZATION_COSTS('<table>') — returns JSON with BuildCosts
(credits) and StorageCosts (TB/month) estimates. Verified hands-on: MaintenanceCosts came
back "NotAvailable" — "Table is too young. Requires 7 day(s) of history" on a brand-new
table — ongoing maintenance-cost estimation needs real observed query/write history over
time, not just the table's current size.ALTER TABLE ... CLUSTER BY (...) — keeps specified column(s) co-located
across micro-partitions as a table grows/churns, preserving pruning effectiveness. Snowflake
performs automatic reclustering in the background (consumes credits); only worth it on
large (multi-TB), frequently-filtered/joined tables — small tables see no benefit and add
needless reclustering cost.SHOW-type queries specifically, the role
must exactly match the role that generated the cached result.UUID_STRING, RANDOM,
RANDSTR), external functions, hybrid table queries, result-affecting config changes, and —
easy to miss — background reclustering/partition consolidation alone, even with no
logical data change.COUNT(*)-style results.VARIANT (max ~16MB
compressed/value, :/bracket notation, FLATTEN() to explode nested arrays/objects) +
unstructured file handling via stages/directory tables (see
Domain 3).SUM, COUNT, AVG, MIN/MAX) plus Snowflake extras
like APPROX_COUNT_DISTINCT (HyperLogLog-based, much cheaper than exact COUNT(DISTINCT) on
huge tables) and semi-structured-aware aggregates.ROW_NUMBER(), RANK(), LAG/LEAD, running totals via
OVER (PARTITION BY ... ORDER BY ...); QUALIFY lets you filter directly on a window
function's result without wrapping the query in a subquery/CTE — a Snowflake-specific
convenience worth knowing by name.SELECT * on wide tables, using QUALIFY instead of nested subqueries, and preferring
set-based operations over row-by-row procedural logic.APPROX_COUNT_DISTINCT might be preferred over exact
COUNT(DISTINCT) at scale?QUALIFY does and why it exists?