Skip to content

Limitations and best practices

This page summarizes supported features, limitations, and best practices.

Quick reference

FeatureSupportedNotes
SELECT, WHERE, GROUP BY, HAVING, ORDER BY, LIMITYes
Column aliases (AS)Yes
Expressions (CASE, CAST, LIKE, BETWEEN, IN, arithmetic)YesFull expression support
EXPLAINYesReturns execution plan as text or JSON
173 scalar functionsYesMath, string, datetime, regex, crypto, array, map, struct, JSON
33 aggregate functionsYesBasic, approximate, statistical, bitwise, boolean, positional
Approximate aggregatesYesapprox_distinct, approx_median, approx_percentile_cont, approx_top_k
Struct / Array / Map column typesYesBracket notation, get_field(), array functions, map functions
CTEs (WITH ... AS)YesCan reference different tables and include JOINs
JOINs (INNER, LEFT, RIGHT, FULL OUTER, CROSS)YesAll standard join types
Implicit joins (comma FROM)Yes
Subqueries (IN, NOT IN)YesNOT IN not supported on nullable columns — use NOT EXISTS instead
Subqueries (EXISTS, NOT EXISTS)Yessemi-join and anti-join patterns
Scalar subqueriesYesIn SELECT, WHERE, HAVING
Derived tables (FROM subqueries)YesCan be nested and joined. LATERAL derived tables not supported.
Self-joinsYesSame table with different aliases
Window functions (OVER)No
SELECT DISTINCTNoUse approx_distinct
OFFSETNo
UNION / INTERSECT / EXCEPTNo
INSERT / UPDATE / DELETENoRead-only
CREATE / DROP / ALTERNoRead-only

For the full SQL syntax, refer to the SQL reference.


Unsupported SQL features

FeatureError
SELECT DISTINCTunsupported feature: SELECT DISTINCT is not supported
OFFSETunsupported feature: OFFSET clause is not supported
UNION / INTERSECT / EXCEPTSet operations not supported
Window functions (OVER)unsupported feature: window functions (OVER clause)
INSERT / UPDATE / DELETEonly read-only queries are allowed
CREATE / DROP / ALTERonly read-only queries are allowed
UNNEST / PIVOT / UNPIVOTNot supported
Wildcard modifiers (ILIKE, EXCLUDE, EXCEPT, REPLACE, RENAME on *)Not supported
Nested (parenthesized) joinsNot supported
LATERAL derived tablesNot supported
LATERAL VIEW / QUALIFYNot supported

Unsupported expression patterns

PatternAlternative
func(DISTINCT ...) on any aggregateUse approx_distinct for counting
PERCENTILE_CONT / PERCENTILE_DISCUse approx_percentile_cont
MEDIANUse approx_median
ARRAY_AGGNo alternative (unsupported for memory safety)
STRING_AGGNo alternative (unsupported for memory safety)
NOT IN subquery on nullable columnsUse NOT EXISTS with a correlated subquery instead

Runtime constraints

ConstraintDetails
Multi-table queriesJOINs, subqueries (IN, EXISTS, scalar, derived tables), and multi-table CTEs are supported. Performance depends on intermediate result size; use WHERE filters to manage join selectivity.
Partitioned and unpartitioned tablesBoth partitioned and unpartitioned Iceberg tables are supported.
Parquet format onlyNo CSV, JSON, or other formats.
Read-onlyR2 SQL is a query engine, not a database. No writes.
now() / current_time() precisionQuantized to 10ms boundaries and forced to UTC.

Common error codes

CodeMeaning
40003Invalid SQL syntax
40004Invalid query (unsupported feature, unknown column, type mismatch)
80001Edge service connection failure (retry)

Best practices

  1. Include time-range filters in WHERE to limit data scanned.
  2. Use specific column names instead of SELECT * for better performance.
  3. Use LIMIT to control result set size.
  4. Use approximate aggregation functions (approx_distinct, approx_median, approx_percentile_cont) instead of exact alternatives on large datasets.
  5. Enable compaction in R2 Data Catalog to reduce the number of files scanned per query.
  6. Use EXPLAIN to inspect the execution plan and verify predicate pushdown.
  7. Use WHERE filters with multi-way joins to reduce intermediate result sizes. Joining three or more large tables without filters can exceed resource limits.
  8. Join large fact tables through dimension tables rather than directly joining two large fact tables. For example, join http_requests to firewall_events through a shared zones dimension rather than cross-joining both fact tables.
  9. Be cautious with COUNT(DISTINCT) across multi-way joins. This combination can produce very large intermediate results. Consider using approx_distinct() or breaking the query into smaller steps.
  10. Use explicit JOIN syntax instead of implicit joins (comma-separated FROM) for readability and to ensure the optimizer can choose optimal join ordering.