PhoenixAI version 4.1
v4.1 was first released on April 9, 2026, and has been maintained since; the most recent patch, 4.1.6, was released on September 30, 2026.
This page describes the 4.1 line as a whole rather than patch by patch. The Upgrade and compatibility section separates what changes when you move to 4.1 from what changed later within the line, because a cluster that has been on 4.1 since launch and a cluster arriving on 4.1.6 today face different lists. Everything else is organized by capability: a feature that arrived in 4.1.0 and was extended in a later patch appears once, in its finished form.
Upgrade and compatibility
Before you upgrade to 4.1
Upgrade to the newest 4.1 patch, not to 4.1.0. 4.1.0 was released before 4.0.9, and several later 4.0 patches added things that 4.1.0 does not recognize. If you created SQL user-defined functions on 4.0.11 or later, a 4.1.0 FE cannot load the metadata that holds them; support returns in 4.1.1. Settings added in 4.0 patches are silently ignored by a 4.1 patch that predates them: 4.1.0 does not recognize scan_lake_partition_num_limit or binary_encoding_format (both back in 4.1.1), and LDAP case-insensitive matching (authentication_ldap_case_insensitive) and authentication-failure caching, added in 4.0.16, arrive in the 4.1 line only with 4.1.6. Choose a 4.1 patch released after the 4.0 patch you run now, and after upgrading confirm that every setting you rely on is still recognized, in fe.conf, in be.conf, and in global variables set with SET GLOBAL. Container deployments in particular should skip 4.1.0: its BE and CN processes can crash at startup, which 4.1.1 fixes.
Take a fresh metadata image before you upgrade. 4.1 no longer recognizes the journal record that 4.0 writes when a table's in_memory property is altered. If such a record has not yet been folded into an image, the 4.1 FE stops on it at startup. Run ALTER SYSTEM CREATE IMAGE on the leader FE and wait until the image reaches every follower before upgrading the first FE.
Downgrade is restricted. After the upgrade, 4.1 writes metadata records that no 4.0 patch recognizes, including records it writes on its own when the recycle bin purges dropped partitions and databases. Roll back only to 4.0.6 or later. To roll back, set metadata_ignore_unknown_operation_type and metadata_ignore_unknown_subtype to true in fe.conf. Objects that only 4.1 understands do not survive a rollback: range-distributed tables, tablet split and merge jobs, SQL digest blacklist entries and external cluster snapshots. In shared-data clusters, Primary Key tables created on 4.1 use a new primary key encoding that 4.0 does not have; contact support before rolling back a cluster that contains such tables.
Settings removed in 4.1 must be renamed or dropped. The session variable enable_pre_agg_top_n_push_down is gone, and materialized_view_subuqery_text_match_max_count is now spelled materialized_view_subquery_text_match_max_count. SET on a removed variable, or naming one in a SET_VAR hint, fails with Unknown system variable, and values set with SET GLOBAL before the upgrade are dropped, recorded only as an error in fe.log, so re-apply them under the new names. The FE configuration item tablet_reshard_split_size is ignored if it remains in fe.conf, and ADMIN SET FRONTEND CONFIG on it returns an error. If you are upgrading from 4.0.8 or earlier, note also two changes that reached the 4.0 line in 4.0.9: dump_log_dir is gone, with fe.dump.log written to sys_log_dir, and log_plan_cancelled_by_crash_be is deprecated in favor of log_plan_on_query_failure.
Defaults that change on upgrade to 4.1
These take effect without any action on your part. None of them is in any 4.0 patch.
-
Materialized views decide how many partitions to refresh per run.
default_mv_partition_refresh_strategymoves fromstricttoadaptive. This applies to every partitioned materialized view without its ownpartition_refresh_strategyproperty, existing views included. Each refresh task now takes as many partitions as fit within about 100 million rows, 20 GB and 64 partitions of base-table data, so refreshes finish in fewer, heavier task runs. To restore the 4.0 behavior cluster-wide, setdefault_mv_partition_refresh_strategy = strict; for one view, runALTER MATERIALIZED VIEW <mv> SET ("partition_refresh_strategy" = "strict"). -
A refresh task can take up to 64 partitions, up from 10.
mv_max_partitions_num_per_refreshmoves from10to64. Set it back to10if refreshes compete with queries for resources. -
When a refresh is split across task runs, the newest partitions go first.
materialized_view_refresh_ascendingmoves fromtruetofalse. Recent data appears in the view sooner after a backfill; a monitoring job that judges progress by the oldest partition needs changing. Set it back totrueto refresh oldest-first. Separately,max_mv_task_run_meta_message_values_lengthmoves from16to8, so partition lists in task-run messages are truncated sooner. -
Shared-nothing clusters use the slot-based Query Queue v2.
enable_query_queue_v2moves fromfalsetotrue. Nothing is queued unless query queues are enabled (enable_query_queue_select,enable_query_queue_loadorenable_query_queue_statistic); if they are, admission is computed from slots, and the global variablesquery_queue_mem_used_pct_limitandquery_queue_cpu_used_permille_limitno longer take effect. To keep the v1 queue, setenable_query_queue_v2 = falseinfe.confand restart the FEs; the item cannot be changed at runtime. Shared-data clusters configure queueing per warehouse and are unaffected. -
ALTER TABLE ... DISTRIBUTED BYruns online in shared-nothing clusters (4.1.0 to 4.1.4).enable_online_optimize_tablemoves fromfalsetotrue, so changing a table's hash distribution or bucket count no longer blocks loads. 4.1.5 sets it back tofalse; see Other operational changes within the line. -
Tablet splitting targets 10 GB tablets.
tablet_reshard_split_size(4 GB) is replaced bytablet_reshard_target_size(10 GB), and one tablet can split into up to 1024 tablets rather than 8 (tablet_reshard_max_split_count). A tablet is split once it reaches twice the target size. Scripts that passtablet_reshard_split_sizetoALTER TABLE ... SPLIT TABLETnow fail withUnknown properties; usetablet_reshard_target_size. -
New shared-data tables use Fast Schema Evolution v2. Tables created on 4.1 have
cloud_native_fast_schema_evolution_v2 = true, so adding, dropping or widening a column updates only FE metadata. Tables created before the upgrade keep the previous behavior until you set the property totrue. See New features. -
VARBINARYwithout a length is stored asVARBINARY(1048576). The documented default is now written into the metadata of new tables and added columns, soSHOW CREATE TABLEandDESCshow the length. CTAS and materialized views keep their previous types. -
KILL QUERYsurfaces as error 1317 (ER_QUERY_INTERRUPTED, SQLSTATE70100) instead of a generic error, so client retry logic can tell a deliberate cancel from a failure. -
<string> IN (<date>, ...)compares as dates. When every item in anINlist is aDATEorDATETIMEof the same type and the left side is a string, the string is now cast to that type rather than the dates being cast to strings.'2024-12-09 00:00:00' IN (DATE '2024-12-09')now matches. Strings that do not parse as dates compare as NULL. Review filters that relied on exact string matching. -
Spark Load uses the 4.1 DPP library.
spark_dpp_versionmoves from1.0.0to the 4.1 version, and the first Spark Load after the upgrade uploads the new library to the Spark repository. Remove any pin ofspark_dpp_versioninfe.conf.
Changes within the 4.1 line that can alter query results
Each of these corrects behavior that was wrong. The previous results were incorrect, so a query whose output changes was returning the wrong answer before — but the change is still visible, and a report or downstream job built on the old output needs checking. Where the same fix shipped in a 4.0 patch, a cluster upgrading from that patch or later already has it.
-
Routine Load no longer skips messages in newly added Kafka partitions (4.1.3). When
property.kafka_default_offsetsis not set and a partition appears after a job has started, the job now reads that partition from the beginning instead of from the end, which silently skipped whatever was produced before the partition was discovered. Expect a burst of older messages the first time a topic gains partitions after the upgrade. A job's first discovery still starts at the end. Setkafka_default_offsetsexplicitly to choose the behavior. -
A shared-data Primary Key load that mixes UPSERT and DELETE for the same key keeps their order (4.1.5). A delete inside a transaction was previously applied after all of that transaction's upserts, wherever it appeared, so a load that upserted a key after deleting it lost the row.
lake_enable_pk_preserve_txn_delete_ordernow defaults totrue. Before rolling back to 4.1.3 or earlier, or running a mixed-version cluster, set it tofalseon every BE and CN. -
Incremental materialized views that use
COUNT(<nullable column>)no longer count NULLs (4.1.2). Views created before the fix hold inflated counts and must be dropped and re-created. -
String-to-number schema changes follow
CASTsemantics (4.1.4).ALTER TABLE ... MODIFY COLUMNfrom a string to a numeric type now stores NULL for values that overflow or do not parse. Previously it stored a wrapped value —'99999999999'toINTgave1215752191— or0for'abc'. -
TABLESAMPLEandANALYZE SAMPLE TABLEtake effect on shared-data tables (4.1.4). The sample options never reached the scan, soTABLESAMPLEreturned every row and sampled statistics were computed from a full scan. (Also in 4.0.17.) -
rewrite_data_fileswith aWHEREclause no longer loses data (4.1.6). Upgrade before compacting Iceberg tables selectively. (Also in 4.0.15.) -
Iceberg and Delta Lake partitions stored as date strings are pruned and deleted correctly (4.1.4). When a partition column is a string holding a date and is compared with a
DATEorDATETIMEvalue, partition pruning, metadataDELETEand equality-delete application now behave correctly; equality deletes were under-applied, so deleted rows came back. -
An Iceberg time-travel read uses the schema and partition spec of the snapshot it targets (4.1.4), not the table's current ones, and a materialized view is no longer used to answer a time-travel query (4.1.5). Materialized view rewrite also stops serving stale results after an Iceberg
rollback_to_snapshot(4.1.4; also in 4.0.14). -
Iceberg v3 tables with deletion vectors, and encrypted Iceberg tables, are rejected (4.1.1). On 4.1.0 a query could ignore deletion vectors and return deleted rows. The query now fails with an error that names the unsupported feature.
-
Oracle columns in JDBC catalogs change type (4.1.0). An Oracle
NUMBERwithout declared precision, previously a string, maps toDECIMAL(38, 6); the scale is set by the catalog propertyoracle.number.default-scale. OracleTIMESTAMPtypes map toVARCHAR(64)rather thanVARCHAR(1048576), or toDATETIMEwithoracle.temporal.to-datetime(ororacle.timestamptz.to-datetime) set totrue. Downstream schemas that expected strings need checking. -
Unsigned Parquet
INT32values are zero-extended (4.1.3); values with the high bit set used to load as negative numbers. Pre-1970 Parquet and ORC timestamps keep their sub-second part on load. -
Parquet
INT64timestamps written as timezone-naive are no longer shifted (4.1.3). WhenisAdjustedToUTC=false,FILES()and broker or stream loads shifted values by the session timezone offset; they are now read as wall-clock values.INT96timestamps nested inSTRUCT,ARRAYorMAPnow receive the same session-timezone shift as top-levelINT96columns. (Also in 4.0.12.) -
LIKEescaping on constant operands follows MySQL 8 (4.1.3), andLIKEwith the_wildcard returns correct rows on columns with a GIN inverted index. (Also in 4.0.13.) -
VARCHAR(N)length is preserved through CTAS (4.1.3) when the source carries an explicit length, instead of being widened toVARCHAR(1048576). (Also in 4.0.12.) -
VARBINARY values nested inside
ARRAY,MAPorSTRUCTare hex-encoded in MySQL result sets (4.1.1). Raw bytes broke text-protocol parsing.binary_encoding_format(hex,base64orraw) andbinary_encoding_level(nestedorall) control the encoding; top-level VARBINARY columns are unchanged by default. (Also in 4.0.10.) -
Ranger row-filter and column-masking policies apply to Hive views in external catalogs (4.1.2). Queries through such a view previously bypassed them. (Also in 4.0.12.)
-
A division with a non-constant divisor is no longer treated as monotonic (4.1.4), so Zone Map pruning no longer drops rows that satisfy a predicate such as
10 DIV c, andNOT MATCHon a GIN inverted index no longer returns NULL rows (4.1.4). (Both also in 4.0.14.) -
List partition pruning no longer discards a partition because its value list contains NULL (4.1.6).
!=,NOT INandIS NOT NULLpredicates, including theIS NOT NULLa planner derives on a join key, previously dropped a whole multi-value partition. Range predicates also map onto expression-partition columns only when the expression preserves order. (List partition fix also in 4.0.16.) -
Query cache results are keyed correctly (4.1.5). The cache digest now includes the scan's schema and join-predicate sub-expressions, and incomplete per-tablet results are no longer stored, so a cached result can no longer be served for a different query. (Partly also in 4.0.14 and 4.0.15.)
-
Date and string functions (4.1.6).
months_diffandyears_diffreturn0within the same month or year rather than-1in some cases, andsubstron invalid UTF-8 no longer returns bytes from neighboring rows. (Also in 4.0.16.) -
Searched
CASE WHENreturning a collection type evaluates each branch only on the rows that select it (4.1.6), so a branch that would raise an error no longer does when no row selects it. Set the BE configurationcase_when_selective_eval_ratioto0to restore the previous evaluation. -
Data Cache keys for external-table files no longer depend on the CPU (4.1.6). 4.1.0–4.1.5 derived these keys from a CRC hash on x86 CPUs with SSE4.2; they are now always MurmurHash3, as in 4.0. On x86 nodes, entries cached by 4.1.0–4.1.5 are not reused, so the external-table Data Cache re-warms once after the upgrade.
Changes within the 4.1 line that can cause a statement to fail
-
Partition guards cover Iceberg and Delta Lake (4.1.3).
allow_lake_without_partition_filter(formerlyallow_hive_without_partition_filter) andscan_lake_partition_num_limitpreviously applied to Hive, Hudi and Paimon only. Both defaults are permissive, but a cluster that setallow_hive_without_partition_filter = falseglobally now also rejects Iceberg and Delta Lake queries without a partition predicate, withPartition pruning is invalid. On 4.1.0 only,scan_lake_partition_num_limitis not recognized; 4.1.1 restores it. -
Incremental materialized views reject what they cannot maintain correctly (4.1.1).
"refresh_mode" = "AUTO"is no longer accepted; onlyINCREMENTALandPCTare. Paimon tables can no longer be base tables.REFRESH ... FORCE, partition-scopedREFRESHand switching refresh mode withALTERare rejected; drop and re-create the view instead.CREATErejects aggregates outside a supported list,DISTINCTaggregates and, from 4.1.2,HAVING. Incremental views no longer serve automatic query rewrite. Check any incremental view created on 4.1.0. -
CREATE STORAGE VOLUMEandALTER STORAGE VOLUMEvalidate the location first (4.1.2). In shared-data clusters, invalid credentials, endpoints or network access fail the statement immediately instead of being persisted and failing later. Setenable_storage_volume_access_check = falseto skip the check. -
Iceberg
NOT NULLcolumns are enforced on write (4.1.5). A NULL now fails withNULL value in non-nullable column '<name>', where it was previously written. -
remove_orphan_filesrejects anolder_thanless than 24 hours old (4.1.5). A cutoff that recent can delete files a concurrent write has not yet committed. If no concurrent writer can be affected, lowericeberg_remove_orphan_files_min_retention_seconds(default86400, dynamically modifiable). -
A materialized view whose Iceberg or external base table drifts becomes inactive at its next refresh (4.1.2) — a changed column type, a dropped column or a dropped table — instead of silently producing NULL rows.
-
Sort key columns of a type the BE cannot encode are rejected (4.1.5), including JSON, complex, floating-point, VARIANT and TIME types, where the BE previously crashed on rewrite. On range-distributed tables,
ALTER TABLE ... ORDER BYthat reorders key columns of a key-derived sort key is rejected (4.1.4). -
ARRAYandMAPconstructors fail rather than corrupt (4.1.4). A constructor whose result exceeds the addressable size of one chunk raisesCapacityLimitExceedinstead of returning corrupted values.pipeline_enable_large_column_checkeris also enabled by default (4.1.2), so a query producing an oversized column fails withLarge column detectedrather than proceeding. Reducechunk_sizeor split the expression. (The checker default is also in 4.0.12, the constructor check in 4.0.14.) -
A static partition clause in an
INSERTinto an Iceberg or Hive table is validated even when a column list is given (4.1.5). A clause naming a non-partition column is rejected instead of ignored. (Also in 4.0.14.) -
TRUNCATE TABLE <catalog>.<db>.<table>checks privileges against the named catalog (4.1.6) rather than the session's current catalog. -
Analysis rejects statements that previously reached the BE (4.1.6):
SELECT DISTINCT ... ORDER BYa column not in the select list, aDISTINCTaggregation overPERCENTILE, and an ASOF JOIN temporal condition that does not compare one column from each side.
Other operational changes within the line
- Online optimize is off by default again (4.1.5).
enable_online_optimize_tablereturns tofalse, so on a cluster upgrading from 4.1.0–4.1.4,ALTER TABLE ... DISTRIBUTED BYblocks writes to the table while it runs, as in 4.0. Set it totrueto keep the online behavior. - Query Queue v2 estimates slots from parallelism by default (4.1.4).
query_queue_slots_estimator_strategydefaults toPBEinstead ofMAX, and a CPU-cost-based estimator,CBE, is added.MAXandMINno longer exist; a cluster or warehouse configured with either is treated asPBEwithout an error. SetMBEorCBEto weigh memory or CPU cost. - Shared-data tablet metadata and transaction logs carry a checksum by default (4.1.5).
lake_enable_protobuf_file_checksummoves totrue, so corruption is detected when the file is read. Files written this way cannot be read by 4.1.0–4.1.2 or by 4.0 patches before 4.0.13. Before rolling back to one of those versions, set it tofalseon every BE and CN; files already written in the new format remain unreadable to the older reader. - Copy-on-write column optimization is off (4.1.2).
enable_cow_optimizationmoves fromtruetofalsebecause a design flaw could crash the BE. Expect a small CPU cost in exchange; turning it back on is not recommended. - Loads into automatic-partition tables open more partitions up front (4.1.2).
max_load_initial_open_partition_numbermoves from32to4096and becomes a ceiling rather than a fixed count: LIST-partitioned tables, and RANGE-partitioned tables loaded byINSERT, Broker Load or Spark Load, open all partitions up to it, while Stream Load and Routine Load into RANGE tables keep 32. The table propertyload_initial_open_partition_numberoverrides it per table. - Shared-data vacuum batches more deletions per request (4.1.3).
lake_vacuum_min_batch_delete_sizemoves from100to200. - Data Cache disk quota grows back after 3 minutes of low usage instead of 2 hours (4.1.6).
datacache_disk_idle_seconds_for_expansionmoves from7200to180, and a quota that auto-adjust shrank to zero now recovers. - The AWS SDK's own HTTP client is used again (4.1.6).
enable_poco_client_for_aws_sdkdefaults tofalse; set it totrueto restore the previous client. - jemalloc's dedicated oversize arena is enabled by default (4.1.6), so allocations of 128 MB or more no longer land in the calling thread's per-CPU arena. This improves reuse of large buffers and reduces fragmentation. Set
oversize_threshold:0insidejemalloc_confto restore the previous layout. - Shared-data Primary Key tablets no longer start a base compaction on their own when deletes accumulate (4.1.6). In 4.1.4 and 4.1.5 the delete thresholds triggered it automatically, which rewrote large update-heavy tablets repeatedly. Set
lake_pk_compaction_base_enable_delete_trigger = trueto restore the trigger;ALTER TABLE ... COMPACTruns a base compaction on demand either way. - An exception that escapes a BE thread-pool task stops the process (4.1.5) instead of being logged and ignored, which could report a task as successful when it had produced nothing. As a temporary mitigation for a crash loop, set
enable_threadpool_catch_task_exception = true. - Result delivery to a slow client has a timeout (4.1.2).
mysql_send_packet_timeout_ms(default 60 seconds) bounds how long the FE waits for a client to read results; set it to0for the previous unbounded wait. - Several settings are renamed; the old names keep working.
scan_hive_partition_num_limitbecomesscan_lake_partition_num_limit(4.1.1) andallow_hive_without_partition_filterbecomesallow_lake_without_partition_filter(4.1.3). On the FE,files_enable_insert_push_down_schemabecomesfiles_enable_insert_push_down_column_type(4.1.1),azure_adls2_oauth2_oauth2_client_endpointbecomesazure_adls2_oauth2_client_endpoint(4.1.2), andslow_lock_log_every_msbecomesslow_lock_log_l2_info_interval_ms(4.1.2). On the BE,txn_commit_rpc_timeout_msbecomesstream_load_thrift_rpc_timeout_ms(4.1.2). - Some configuration items are removed.
lock_manager_enabled(4.1.2) is gone, so FE metadata locks always use the lock manager.skip_pk_preload(4.1.1),enable_pk_index_eager_build(4.1.4) andsegment_sort_key_sample_row_interval(4.1.6, replaced bysort_key_max_samples_per_tablet) are also gone. A leftover entry infe.conforbe.confis ignored at startup, but a runtime update that names one fails, so remove them from automation scripts. - The FE starts listening only after startup materialized view activation completes (4.1.5), controlled by
enable_mv_startup_activation_gate(defaulttrue). An FE with many materialized views takes longer to start serving, but is usable once it does. - A statistics health figure pinned near
1.0for tables with many stale partitions is corrected (4.1.5), so auto-ANALYZE may re-analyze such tables after the upgrade. paimon.option.cache-enabled = falsedisables the Paimon metadata cache again (4.1.6), and HDFS files are no longerhsynced before close.
New features
Enterprise-only capabilities
These are available in PhoenixAI and not in open-source StarRocks.
-
Cross-region disaster recovery for shared-data clusters (Beta)
Cluster snapshots have protected against losing a cluster, but not against losing a region: the snapshot sat in the same storage as the data it protected. From 4.1, an automated cluster snapshot can be external —
ADMIN SET AUTOMATED CLUSTER SNAPSHOT ON ... PROPERTIES ("snapshot_scope" = "external"). Each run then writes a full FE metadata image and copies the data files that changed since the previous run to a storage volume in a second region, and a cluster in that region can restore from the latest snapshot without the primary cluster or its storage. The amount of data at risk is bounded by the snapshot interval. Awarehouseproperty chooses which warehouse does the copying.Later patches hardened the feature: the interval survives FE restarts and snapshots stay restorable across tablet split and merge (4.1.3–4.1.4), each snapshot records its scope and source storage volumes and restore is replay-safe (4.1.5), and cleanup is retryable (4.1.6). Run 4.1.6 or later if you rely on it.
-
Resource groups scoped to warehouses
A resource group previously applied to every warehouse in a cluster. From 4.1.0 the
warehousesattribute restricts a group to the named warehouses: the FE considers it only for queries running there, and nodes in other warehouses hold it inactive. A group scoped this way sets its CPU share withcpu_weight_percentorexclusive_cpu_percent, which express the soft weight and the hard reservation as a percentage of each node's cores, so one definition behaves the same in warehouses of different sizes. -
Query queue policy per warehouse
From 4.1.4, Query Queue v2 can be tuned for each warehouse with
ALTER WAREHOUSE:query_queue_slots_estimator_strategy,query_queue_v2_concurrency_level,query_queue_v2_mem_bytes_per_slot,query_queue_v2_cpu_costs_per_slotandquery_queue_v2_schedule_strategy. Properties left unset fall back to the FE configuration, so an interactive warehouse and a batch warehouse no longer have to share one admission policy. -
The real client address survives a load balancer
Behind a TCP load balancer, every connection appeared to come from the balancer, so host-restricted accounts,
SHOW PROCESSLISTand the audit log all saw the wrong address. From 4.1.2 the FE accepts a PROXY protocol v1 header on the MySQL port from the networks listed inmysql_proxy_protocol_networks, and uses the client address it carries for authentication, the process list and auditing. It is off by default. List only your load balancers' ranges, because any peer allowed to send the header can claim any client address. Only v1 is supported, so a load balancer that emits v2 is not compatible.
Shared-data architecture and storage
-
Tablets split and merge as the data changes (Beta)
A hash-bucketed table fixes its bucket count when it is created. When data grows unevenly — tenants of different sizes, or a hot key range — some tablets become too large while others stay nearly empty, and the only remedy was to rebuild the table. 4.1 adds range-based distribution for shared-data clusters: rows are ordered by the sort key, each tablet covers a contiguous key range, and a tablet that grows past
tablet_reshard_target_size(10 GB by default) is split automatically. Adjacent tablets can be merged when they shrink, and the newALTER TABLE ... MERGE TABLETmerges on demand alongside the existingALTER TABLE ... SPLIT TABLET.The line extended the feature in every patch. From 4.1.1, range-distributed tables can form colocate groups and take part in colocate joins, extended to outer, semi and anti joins in 4.1.4. From 4.1.2, the first bulk load into a range-distributed table samples the incoming sort keys and pre-splits its tablets so the load runs in parallel from the start; this covers
INSERT ... SELECT FROM FILES()and Broker Load in 4.1.2,INSERT ... SELECTfrom another table in 4.1.3, and Iceberg sources and overwrite loads in 4.1.5. Pre-splitting is on by default for eligible tables and can be turned off per session withenable_tablet_pre_split = false.Range distribution is opt-in in 4.1: set the FE configuration
enable_range_distributiontotrue, and new tables created without aDISTRIBUTED BYclause use it. Merging is also off by default; settablet_reshard_enable_tablet_mergetotrueto allow it. -
Large tablets no longer bottleneck on a single thread (Beta)
In a shared-data cluster each tablet was compacted, published and indexed by one thread, so a large tablet became a serial bottleneck however many cores the Compute Node had. 4.1 parallelizes work inside a tablet across the write path. Compaction splits a large tablet's input into parallel subtasks, by default up to three per tablet, set cluster-wide by
lake_compaction_max_parallel_defaultor per table by thelake_compaction_max_parallelproperty. MemTable finalize, flush and spill merge run in parallel during loads; the cloud-native Primary Key index is range-split and compacted in parallel; and Primary Key publish, partial updates and conditional updates run in parallel within the tablet (4.1.1). The practical effect is that fewer, larger tablets — with less FE metadata and fewer small files — no longer cost load latency or compaction backlog. These are on by default.From 4.1.4, Primary Key tablets also support base compaction, which rewrites delete-heavy data to reclaim deleted rows. Run it with
ALTER TABLE ... COMPACT. In 4.1.4 and 4.1.5 it is also triggered automatically by delete volume; from 4.1.6 that trigger is opt-in throughlake_pk_compaction_base_enable_delete_trigger. -
Column changes on shared-data tables complete when the statement returns
With Fast Schema Evolution v2,
ALTER TABLEadding, dropping or widening a column updates only FE metadata rather than rewriting tablet metadata in object storage, and finishes in seconds however many partitions and tablets the table has. In 4.1 this is controlled per table by thecloud_native_fast_schema_evolution_v2property, which is on for tables created on 4.1; set it totrueon older tables withALTER TABLE ... SET.ALTER MATERIALIZED VIEW ... ADD COLUMNandDROP COLUMNlet a single-table aggregate materialized view gain or lose a column without being rebuilt. -
Full-text inverted indexes on shared-data tables (Beta)
Inverted indexes used CLucene, which works only in shared-nothing clusters. 4.1 adds a built-in implementation that works in both architectures and is chosen automatically in shared-data clusters, so
INDEX ... USING GINacceleratesMATCHand text-filter predicates on cloud-native Duplicate Key and Primary Key tables. Thedict_gram_numproperty adds an n-gram index over the term dictionary, which speeds upLIKEand wildcard searches, andMATCH_ALLjoinsMATCH_ANY. As with other inverted indexes, set the FE configurationenable_experimental_gintotruebefore creating one. -
Restore a single table from a cluster snapshot
Recovering one table that had been dropped or damaged meant restoring the whole cluster to a snapshot and losing everything written since. From 4.1.0,
RESTORE TABLE <source> FROM SNAPSHOT <snapshot> TO TABLE <new_table>rebuilds one table, as it was in a finished cluster snapshot, under a new name beside the live data, so you can compare it with the current table or swap it in. The target table must not already exist. -
Migrate between shared-data clusters
The cross-cluster migration tool previously moved data from shared-nothing to shared-data clusters only. From 4.1 it also replicates tables, including range-distributed tables, from one shared-data cluster to another, copying files in parallel, verifying file integrity and skipping files already present on the target. The target must run 4.1 or later.
-
A publish queue stuck on one transaction can be cleared
When a committed transaction on a shared-data table can never be published — because its transaction log or a segment file was lost — every later load to the table queues behind it. From 4.1.2,
ADMIN SKIP COMMITTED TRANSACTION <txn_id> REASON '...'finalizes that one transaction as a no-op so the queue drains without dropping the partition. It applies to load and compaction transactions on tables withfile_bundlingenabled. The transaction's data is discarded irreversibly, so the statement requires the SYSTEM OPERATE privilege and is rejected unlessenable_admin_skip_committed_txnis set totrue. -
Cache state is visible per tablet
The
[_CACHE_STATS_]table hint, as inSELECT * FROM <table> PARTITION(<p>) [_CACHE_STATS_](the square brackets are literal), returns, for each tablet of a cloud-native table, the bytes cached locally and the tablet's total size, which shows whether a slow query reads from object storage and how much of a table aCACHE SELECTwarmed.CACHE SELECTon a Primary Key table now also warms the Primary Key index, and dropping a table or partition evicts its cached data immediately (lake_enable_drop_tablet_cache, on by default). -
Stream Load and Merge Commit honor the user's default warehouse. A request without a
warehouseheader runs in the warehouse set as the user'ssession.warehouseproperty, rather than always indefault_warehouse. -
Routine Load can load message metadata (4.1.4).
INCLUDE METADATA (...)inCREATE ROUTINE LOADexposes Kafka or Pulsar metadata such as partition, offset and timestamp as loadable columns. -
Shared-data scans skip segments by sort-key range. A scan skips segments whose sort-key range cannot satisfy the query's predicates without opening them (
enable_lake_segment_metadata_filter, on by default). -
Multi-table transactions can be batch-published (4.1.5) with
lake_enable_batch_publish_multi_table = true, which removes the serialization CDC micro-batches fanning out to many tables hit. Enable it only after every FE runs 4.1.5 or later.
Lakehouse
-
Rows can be deleted from Iceberg tables
A row-level change to an Iceberg table had to go through another engine. From 4.1.0,
DELETE FROM <iceberg_table> WHERE ...runs in PhoenixAI: it writes Iceberg position delete files and commits them as a new snapshot, without rewriting data files. TheWHEREclause is required and can include subqueries; partition clauses,USINGandWITHare not supported, and the table's data files must be Parquet. Each commit records the engine, its version and the PhoenixAI user in the snapshot summary. -
TRUNCATE TABLEempties Iceberg tables and Hive managed tablesFrom 4.1.0,
TRUNCATE TABLEapplies to Iceberg tables and to Hive managed tables in an external catalog. On Iceberg it commits a snapshot that removes every data file, so history stays available for time travel until the snapshots expire; Iceberg truncates whole tables only. On Hive,TRUNCATE TABLE <t> PARTITION (col = value, ...)truncates the named partitions; external Hive tables are rejected. Delta Lake and Paimon tables do not supportTRUNCATE. -
Iceberg maintenance gains procedures and named arguments
Iceberg maintenance in 4.0 was a fixed set of
ALTER TABLE ... EXECUTEoperations taking positional arguments. From 4.1.0 each operation is a procedure that also accepts named arguments, as inEXECUTE expire_snapshots(older_than = '...', retain_last = 2). New in 4.1 areretain_lastforexpire_snapshots;locationforremove_orphan_files, which limits the scan to a subdirectory;rewrite_manifests, which merges small manifests by partition;add_files, which adds existing Parquet or ORC files to an Iceberg table from a Hive table or a storage location without copying them; andCALL <catalog>.system.register_table(...), which registers an existing table from its metadata file. Together these let a table be migrated from Hive or adopted from another catalog and then kept healthy from SQL. -
Iceberg v3 row lineage and default values
On Iceberg v3 tables, every row has a stable identity:
_row_idand_last_updated_sequence_numbercan be selected like ordinary columns, which is what change-tracking and deduplication jobs need. From 4.1.1,rewrite_data_fileswrites these fields into rewritten files, so row identity survives compaction. Columns on v3 tables can carry a default value, set inCREATE TABLEor withALTER TABLE ... ADD COLUMN ... DEFAULT; anINSERTthat omits the column writes the default, and files that predate the column read it back as the default. New tables are still created as v2 unless you set"format-version" = "3". -
VARIANT for semi-structured Iceberg data (Beta)
Iceberg tables whose Parquet files use the variant encoding can be queried directly. VARIANT columns are recognized automatically, values are extracted with
variant_queryand the typedget_variant_*functions, and they can be cast to scalar,ARRAY,MAPorSTRUCTtypes. Only unshredded variant values are supported, and VARIANT is not available for native tables. -
Incremental materialized views over Iceberg (Beta)
A partition-based refresh recomputes every partition that changed, so a few thousand appended rows can cost a full partition's worth of work. With
"refresh_mode" = "INCREMENTAL", a materialized view over Iceberg tables consumes only the snapshots appended since its last refresh and merges the result into the view, which is stored as a Primary Key table. The first refresh builds a full baseline. Supported queries are filters, projections,UNION ALL, inner and cross joins, and aggregations from a supported list that includesCOUNT,SUM,AVG,MIN,MAX,ARRAY_AGG, approximate and bitmap distinct counts, and HLL, bitmap and percentile unions (extended in 4.1.1 through 4.1.3). An unsupported query is rejected atCREATEtime with the reason. Incremental views do not take part in automatic query rewrite, so query them directly; see Upgrade and compatibility for what changed after 4.1.0. -
Concurrent writes to one Iceberg table no longer collide at commit
Iceberg commits are optimistic, so two loads committing to one table at the same moment could fail with a conflict. From 4.1.0, commits to the same table are queued and applied one at a time while different tables still commit in parallel. This is on by default and controlled by
enable_iceberg_commit_queue,iceberg_commit_queue_timeout_seconds(default 300) andiceberg_commit_queue_max_size(default 1000). Global shuffle on write now routes rows by the transformed partition value forbucket,truncateand time transforms, so each partition is written by fewer writers and produces fewer, larger files; from 4.1.1, tables partitioned by a transform of aTIMESTAMPTZcolumn can be written as well. -
Paimon time travel and views
A query can pin a Paimon table to a snapshot ID, to the latest snapshot at or before a timestamp, or to a branch or tag (
'branch:<name>','tag:<name>'), which gives reproducible reads and lets you compare branches. From 4.1.2, Paimon views can be created, listed, queried and dropped through a Paimon catalog, with table references inside them resolved against the Paimon catalog. -
AWS Glue tables with partition projection are readable. Athena partition projection computes partitions from table properties rather than storing them in the catalog, so such tables appeared unpartitioned or failed in 4.0. Enum, integer, date and injected projections are now evaluated during partition listing and pruning.
-
JDBC catalogs map more source types and hold connections better. PostgreSQL
TIME,timetz,timestamptz,jsonandjsonbcolumns map toTIME,DATETIMEandJSON, PostgreSQL column comments are shown, and MySQLBINARYandVARBINARYmap toVARBINARY. Pooled connections are recycled before the remote side times them out (jdbc_connection_max_lifetime_ms,jdbc_connection_keepalive_time_ms), database lists are cached, and from 4.1.3 row counts for MySQL, PostgreSQL and ClickHouse tables are fetched asynchronously for planning. See Upgrade and compatibility for the Oracle type changes. -
FILES()takes an explicit schema (4.1.2)."schema" = "col TYPE, ..."declares the columns to read and their types instead of inferring them, which keeps a pipeline over drifting or deeply nested files stable. From 4.1.1, theINSERTproperty"enable_push_down_schema" = "true"reshapes the inferred schema to the target table's columns. -
More Hive layouts are readable. Hive tables stored as OpenX JSON, Hive tables partitioned on
FLOAT,DOUBLEorDECIMALcolumns, and, from 4.1.1, Avro tables through a native reader that supportsavro.schema.literalandavro.schema.url. The native Avro reader is opt-in: setavro_use_jni_reader = false. The ORC writer supportsMAP. -
One cluster can reach several HDFS HA clusters (4.1.1). HA settings such as
dfs.nameservicescan be declared in a catalog'sPROPERTIES, and both FE and BE apply them, so each catalog can point at a different HDFS HA cluster. -
Iceberg REST catalogs without an STS work with vended credentials. When a catalog returns no per-table credentials, PhoenixAI uses the storage credentials the catalog publishes in its configuration endpoint before falling back to the credentials set on the catalog.
-
Elasticsearch 9 is supported by Elasticsearch catalogs and external tables (4.1.6).
Query execution
-
Recursive common table expressions
WITH RECURSIVElets a query refer to itself, so an organizational chart, a bill of materials or a graph of linked records can be walked in SQL rather than in application code or with a fixed number of self-joins. The anchor member produces the first level, and the recursive member runs again on each level's output until it returns no rows or reachesrecursive_cte_max_depth(default 5). Reaching the depth limit raises an error rather than silently truncating the result. The feature is off by default; setenable_recursive_cte = trueto use it. -
ORDER BY <aggregate> LIMIT ngets cheaperFor a query that ranks groups by an aggregate and keeps the top few, the aggregation now maintains a heap of the current top values and publishes it as a runtime filter, so groups that cannot reach the top N are discarded before they are fully aggregated and shuffled. TopN operators can also spill to disk, so a large
ORDER BY ... LIMITno longer fails for lack of memory when spilling is enabled. -
Shared expressions in join conditions are computed once
When a join's
ONclause repeats an expensive expression — the sameCAST,regexp_extractor JSON path in several conjuncts — it is evaluated once per row and reused. Reuse previously applied to scan and outer-joinWHEREpredicates; it now also covers theONpredicates of inner hash joins and nested-loop joins. -
Query Queue v2 shows its work. With
enable_extended_explain = true,EXPLAINreports how many slots a query would request and the state of the queue, so you can see why a query would wait before running it. -
ETL execution mode does more.
SET exec_mode = 'ETL'now enables dependent-event waiting and Query Queue v2 admission alongside spilling and the phased scheduler, and switching back to the default mode restores your global settings rather than forcing spilling and phased scheduling off. The mode is not on by default. -
The window-function skew hint can name the skewed column and value (4.1.1), so a hot
PARTITION BYvalue is split into its own branch rather than processed by one driver. -
Shared-data scans spread work evenly across pipeline drivers, so a single large tablet no longer leaves most drivers idle.
SQL and functions
- New functions:
array_top_n,arrays_zip,json_pretty,json_set,map_entries,sum_map,initcap,current_timezone,sec_to_time,weekday,raise_errorandai_query;uuid_v7anduuid_v7_numeric(4.1.1) for time-ordered UUIDs;query_id()(4.1.2); andget_query_dump_from_query_id(4.1.1). - SQL UDFs (4.1.1):
CREATE FUNCTION f(a INT, b INT) RETURNS a + bdefines a function as a SQL expression, with no jar to build. Java UDF files can be loaded from S3, Java UDFs acceptDECIMALand variable-length argument lists, and Python UDFs accept nestedARRAYandMAP. - Syntax:
WHERE,ORDER BYandLIMITon mostSHOWstatements;ALTER TASK;ORDER BY ALL;DATE_PARTas an alias forEXTRACT; expression column defaults, includingARRAY,MAPandSTRUCTliterals and defaults forJSON,HLL,BITMAPandVARBINARYcolumns;REFRESH CONNECTIONS, which pushes changed global variables to open sessions; andCREATE TABLE ... AS WITH ... SELECTin the Trino dialect (4.1.1). - The
STRUCT_CAST_BY_NAMESQL mode matchesSTRUCTfields by name when casting, soUNION ALLbranches that declare the same fields in different orders can be combined. - The default argument of
lagandleadcan be a column,percentile_approxaccepts an array of percentiles,min_byandmax_byacceptSTRUCTinputs, andarray_generateworks overDATEranges.
Security and authentication
-
A query pattern can be blocked by its digest
The SQL blacklist matches regular expressions against the statement text, which makes it awkward to block one runaway report without catching statements that resemble it, or to keep blocking it when its literals change. From 4.1.0,
ADD SQL DIGEST BLACKLIST <digest>(the digest unquoted) blocks every statement with the same SQL digest whatever its constants;SHOW SQL DIGEST BLACKLISTlists the entries andDELETE SQL DIGEST BLACKLISTremoves them. Entries are persisted and apply on every FE. Enforcement requiresenable_sql_blacklist = trueand SQL digest computation (enable_sql_digest = true), and covers queries,INSERTand CTAS. -
The HTTP APIs can be closed to anonymous callers
From 4.1.3,
enable_http_auth = trueon FEs and BEs requires Basic Auth on every external HTTP endpoint and restricts the license and warehouse endpoints to privileged users. Internal traffic and health and metrics probes stay exempt, so monitoring keeps working. It is off by default and requires a restart to change; before enabling it, check scripts that call/api/...anonymously. -
LDAP and Active Directory logins behave the way the directory does (4.1.6). Groups can be resolved from a user's
memberOfattribute, group names are matched without regard to case, andauthentication_ldap_case_insensitive = truematches user names case-insensitively as well.ALTER GROUP PROVIDERchanges a provider's properties in place, users from an LDAP security integration can authenticate over HTTP, Stream Load and Arrow Flight, and LDAP and group-provider calls have timeouts. (All butALTER GROUP PROVIDERis also in 4.0.16.) -
Hardening switches, off by default (4.1.6):
authorization_enable_query_profile_access_check = truelimits a user to their own query profiles unless they hold SYSTEM OPERATE, andfiles_require_explicit_credentials = truestopsFILES()from falling back to the node's own credentials. (Both also in 4.0.16.) -
Literal values can be kept out of logs.
enable_sql_desensitize_in_log = truereplaces literal values in SQL before it reaches the audit log, query details and profiles; query dumps (enable_desensitize_query_dump) andEXPLAINoutput (enable_desensitize_explain) have their own switches. Credentials inSUBMIT TASKstatements are masked in the task views, and UDF file paths no longer appear inSHOW FUNCTIONS. -
TLS cipher suites are configurable.
ssl_cipher_whitelistandssl_cipher_blacklisttake comma-separated cipher names or regular expressions, so weak suites can be removed from the FE's TLS endpoints. -
BEs and CNs can authenticate to S3 with an AWS WebIdentity token file (4.1.2), matching the FE.
Observability
- FE threads can be inspected with SQL.
information_schema.fe_threadslists every thread on every FE with its state and CPU time, so a stuck or CPU-bound FE can be diagnosed with a query before reaching forjstack. - Materialized view refresh is observable (4.1.3).
information_schema.materialized_view_refresh_jobsshows each refresh as a job, andinformation_schema.materialized_viewsreports each view's refresh mode, trigger, warehouse, resource group, last refresh time and why it is not used for rewrite. - The audit log says why a statement failed (4.1.6). It records the error message the client received, truncated at
audit_log_error_message_max_length(default 1024), and DML into Iceberg, Hive orFILES()and asynchronous materialized view refreshes report real scan and CPU figures.custom_session_name(4.1.1) tags a session in the audit log, andaudit_stmt_before_execute(4.1.2, also in 4.0.12) can record a statement when it starts. - Internal queries — statistics collection, task runs and materialized view refreshes — appear in
SHOW PROC '/current_queries'and can be stopped withKILL QUERY(4.1.2), and load profiles can be written tofe.profile.log(enable_print_load_profile_to_log). - The FE web UI can analyze a query profile and show its formatted SQL, and process profiles cover BE nodes as well as FEs.
GET /api/v2/cluster_summaryreturns database and table counts, disk capacity and node counts as JSON. - New metrics cover Data Cache usage on
/metrics, FE and lake compaction,ALTER TABLEcolumn operations and Thrift server queue timeouts;EXPLAIN COSTScan be included in the query profile (enable_explain_in_profile, 4.1.5).
Improvements
Six patch releases carry several hundred further improvements. The themes most likely to be visible in your workload:
-
Optimizer and execution
Scans read predicate columns first, ordered by selectivity, and materialize the remaining columns only for surviving rows. Full sorts compare strings through a prefix-inlined layout, shuffle exchange uses a faster hash function, and join reordering covers conditions built from expressions over both inputs. Skew is detected more precisely and can be forced for
GROUP BYwithenable_force_group_by_skew_eliminate_when_skewed(4.1.1).UNNESTavoids copying nullable arrays and expands multi-array input incrementally, which removes a common out-of-memory pattern for wide arrays (4.1.6), and Parquet, ORC and CSV reads are bounded by the query memory limit. -
External-table statistics
Statistics on external tables are cheaper to collect: PhoenixAI tracks which columns of an Iceberg, Hive or other external table appear in predicates,
ANALYZE SAMPLE TABLE ... PREDICATE COLUMNScollects only those (4.1.5), all requested columns are gathered in one scan, and Iceberg collection stops at a configurable byte and file budget. Hive and Hudi row counts account for file compression, and Elasticsearch, Kudu andFILES()sources are estimated from metadata or file sizes. Better estimates mostly show up as better join orders over external data. -
Iceberg reads
TopN queries with aggregation push a runtime filter into Iceberg scans (4.1.1), a compound
ANDpredicate is pushed down to file pruning even when only some of its terms translate (4.1.2), and catalog-cache lookups lock per table rather than per catalog, which removes a bottleneck under concurrent queries. -
Memory
jemalloc decay can tighten as resident memory nears the memory limit (
enable_jemalloc_decay_under_rss_pressure, off by default, 4.1.6), and on arm64 a 4K-page jemalloc variant is chosen at startup with ajemalloc_page_sizeoverride (4.1.5). A guard stops collecting global dictionaries that keep being invalidated (enable_dict_thrash_guard, on by default, 4.1.6). -
Security dependency upgrades
Across the line: Netty to 4.1.137.Final, Thrift to 0.24.0, transitive Jetty libraries pinned to patched versions, gRPC aligned for CVE-2025-55163, Apache HttpCore 5.4.3 and HttpClient 5.6.4, Apache Ranger 2.9.0, Bouncy Castle 1.85, ZooKeeper 3.8.7 and 3.9.6, the PostgreSQL JDBC driver to 42.7.12, and the Broker's Tomcat to 9.0.121 and commons-lang3 to 3.20.0 for CVE-2025-48924; and removal of vulnerable transitive dependencies, including
bcprov-jdk15on, the OkHttp 2.x line andavro-ipc.