This is an automated email from the ASF dual-hosted git repository.

yiguolei pushed a commit to branch branch-4.1
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/branch-4.1 by this push:
     new 4aeca3f9d77 branch-4.1 [improvement](statistics) Stop collecting hot 
value in the linear sample estimator (#69209) (#69379)
4aeca3f9d77 is described below

commit 4aeca3f9d778359c3bc1794cb0c63b37252d013b
Author: minghong <[email protected]>
AuthorDate: Tue Oct 27 09:51:09 2026 +0800

    branch-4.1 [improvement](statistics) Stop collecting hot value in the 
linear sample estimator (#69209) (#69379)
    
    ### What problem does this PR solve?
    
    Pick #69209 from master to `branch-4.1` (squash commit `a1a93fc4302`,
    cherry-picked as `b75aadfbb26`).
    
    `LINEAR_ANALYZE_TEMPLATE` collected hot values in a third CTE: it
    grouped the sampled column by value, counted each group, and kept the
    top `hot_value_collect_count` groups. That CTE re-reads the whole sample
    and is the dominant cost of the template — the one sample analyze picks
    for a single distribution column / single unique key column — and its
    cost is not bounded by the sample size for the full-scan fallback.
    
    This PR removes that CTE. `hot_value` keeps its position in the result
    set and is reported as `NULL`, exactly like `FULL_ANALYZE_TEMPLATE` and
    `MERGE_PARTITION_TEMPLATE` already do, and every reader already treats
    `NULL` as "not collected" (`ColumnStatistic.hotValues == null`). Hot
    values are still collected by `DUJ1_ANALYZE_TEMPLATE`, which derives
    them from the grouped sample it already builds for the NDV estimate.
    
    The params that only served the removed CTE (`subStringColName`,
    `rowCount2` on the linear path, `hotValueCollectCount`) are now filled
    for the DUJ1 algorithm only.
    
    ### branch-4.1 adaptation
    
    branch-4.1 still has a flat `org.apache.doris.statistics` package (no
    `analysis/` / `model/` split), so the change is mapped onto:
    
    -
    `fe/fe-core/src/main/java/org/apache/doris/statistics/BaseAnalysisTask.java`
    -
    `fe/fe-core/src/main/java/org/apache/doris/statistics/OlapAnalysisTask.java`
    -
    `fe/fe-core/src/main/java/org/apache/doris/statistics/ColumnStatistic.java`
    -
    
`fe/fe-core/src/test/java/org/apache/doris/statistics/OlapAnalysisTaskTest.java`
    
    Skipped because the corresponding code does not exist in branch-4.1:
    
    - The `AnalyzeCommand` rejection-message change and its test update.
    branch-4.1 has no `WITH HOT VALUE` clause at all (no `HOT` token in the
    Nereids lexer, no `PROPERTY_COLLECT_HOT_VALUE` in `AnalyzeProperties`),
    and `AnalyzeCommand.validate` has no such check. For the same reason
    #69225 (accept `WITH HOT VALUE` on a sample analyze) is a no-op for
    branch-4.1 and is not included here.
    - `PluginDrivenSampleAnalysisTask` (and its `subStringColName` fix) does
    not exist in branch-4.1; the legacy `HMSAnalysisTask` is left unchanged.
    - `test_full_analyze_hot_value.groovy` is master-only.
    
    `physical_agg_regulator`: branch-4.1 cannot ask for hot values
    explicitly, and its tables are distributed by a single column, so every
    sample analyze of them now uses the linear estimator and collects no hot
    value. The expected plan is regenerated accordingly — the skew-aware
    `hashAgg[LOCAL] + PhysicalDistribute[DistributionSpecExecutionAny]`
    branch disappears from the `!skew` case.
    
    ### Behaviour changes
    
    - A sample analyze no longer collects hot values for columns estimated
    with the linear estimator: a single distribution column / single unique
    key column, and any sample analyze that falls back to a full table scan.
    - The planner consequences (`ChildrenPropertiesRegulator` no longer
    picks the skew-aware aggregation shape, `ShuffleKeyPruneUtils` skips the
    shuffle-key prune, `SkewJoin` finds no hot value,
    `DecomposeRepeatWithPreAggregation` treats the missing hot value as
    balanced) change plan quality only: every consumer null-checks "not
    collected" and none of them produces a wrong result.
    
    ### Verification
    
    - FE build: `BUILD SUCCESS`.
    - Unit tests: `OlapAnalysisTaskTest` 17/17, `HMSAnalysisTaskTest` 8/8.
    - Regression (local 1 FE + 1 BE cluster):
      - `test_hot_value` ✅
      - `hot_value_analyze_sync` ✅
      - `physical_agg_regulator` ✅ (with the regenerated expected plan)
    
    ### Release note
    
    Sample analyze no longer collects hot values for columns that use the
    linear NDV estimator (single distribution / single key column, and the
    full-scan fallback of a sample analyze), which removes a second
    aggregation over the sampled data. Hot values are still collected by
    sample analyze for columns estimated with DUJ1.
    
    ### Check List (For Reviewer who merge this PR)
    
    - [ ] Confirm the release note
    - [ ] Confirm test cases
    - [ ] Add branch pick label
---
 .../apache/doris/statistics/BaseAnalysisTask.java  | 25 ++++++++++-----------
 .../apache/doris/statistics/ColumnStatistic.java   |  3 ++-
 .../apache/doris/statistics/OlapAnalysisTask.java  | 18 ++++++++-------
 .../doris/statistics/OlapAnalysisTaskTest.java     | 19 +++++++---------
 .../agg_strategy/physical_agg_regulator.out        |  4 +---
 .../stats/col_stats/hot_value_analyze_sync.groovy  | 12 +++++++---
 .../agg_strategy/physical_agg_regulator.groovy     |  6 +++++
 .../suites/statistics/test_hot_value.groovy        | 26 +++++++++++-----------
 8 files changed, 61 insertions(+), 52 deletions(-)

diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/statistics/BaseAnalysisTask.java 
b/fe/fe-core/src/main/java/org/apache/doris/statistics/BaseAnalysisTask.java
index 2707d28ca6d..8918e7e5850 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/statistics/BaseAnalysisTask.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/statistics/BaseAnalysisTask.java
@@ -107,6 +107,14 @@ public abstract class BaseAnalysisTask {
             + "FROM (SELECT `${colName}`${lengthAssert} "
             +     "FROM `${catalogName}`.`${dbName}`.`${tblName}` ${index}) 
__lc_t";
 
+    // Hot values are intentionally NOT collected by the linear estimator. The 
extra
+    // GROUP BY over the sampled column re-reads the whole sample and is the 
dominant cost
+    // of this template, which is used for every single distribution / single 
key column
+    // sample analyze. `hot_value` keeps its position in the result set and is 
reported as
+    // NULL, which every reader treats as "not collected" (see 
ColumnStatistic#hotValues),
+    // so the row layout stays identical to that of the other templates. Hot 
values are
+    // still collected by DUJ1_ANALYZE_TEMPLATE, which derives them from the 
grouped sample
+    // it already builds for the NDV estimate.
     protected static final String LINEAR_ANALYZE_TEMPLATE = "WITH cte1 AS ("
             +     "SELECT `${colName}`${lengthAssert} "
             +     "FROM `${catalogName}`.`${dbName}`.`${tblName}` ${index} 
${sampleHints} ${limit} ${preAggHint}), "
@@ -124,19 +132,10 @@ public abstract class BaseAnalysisTask {
             +     "SUBSTRING(CAST(${min} AS STRING), 1, 1024) AS `min`, "
             +     "SUBSTRING(CAST(${max} AS STRING), 1, 1024) AS `max`, "
             +     "${dataSizeFunction} * ${scaleFactor} AS `data_size`, "
-            +     "NOW() FROM cte1), "
-            + "cte3 AS ("
-            +     "SELECT IFNULL(GROUP_CONCAT(CONCAT("
-            +         "REPLACE(REPLACE(t.`column_key`, \":\", \"\\\\:\"), 
\";\", \"\\\\;\"), "
-            +         "\" :\", ROUND(t.`count` / ${rowCount2}, 2)), \" ;\"), 
'') "
-            +         "as `hot_value` "
-            +     "FROM ("
-            +         "SELECT ${subStringColName} as `hash_value`, "
-            +         "MAX(`${colName}`) as `column_key`, "
-            +         "COUNT(1) AS `count` "
-            +         "FROM cte1 WHERE `${colName}` IS NOT NULL "
-            +         "GROUP BY `hash_value` ORDER BY `count` DESC LIMIT 
${hotValueCollectCount}) t) "
-            + "SELECT * FROM cte2 CROSS JOIN cte3";
+            +     "NOW() AS `update_time`, "
+            +     "null as `hot_value` "
+            +     "FROM cte1) "
+            + "SELECT * FROM cte2";
 
     protected static final String DUJ1_ANALYZE_TEMPLATE = "WITH cte1 AS ("
             + "SELECT MAX(t0.`col_value`) as `col_value`, COUNT(1) as `count`, 
SUM(`len`) as `column_length` "
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/statistics/ColumnStatistic.java 
b/fe/fe-core/src/main/java/org/apache/doris/statistics/ColumnStatistic.java
index 2ae8cc53145..d3b8613a40f 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/statistics/ColumnStatistic.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/statistics/ColumnStatistic.java
@@ -98,7 +98,8 @@ public class ColumnStatistic {
     public final String updatedTime;
 
     /**
-     * hotValues == null: not collected (e.g. full analyze). Do NOT use for 
optimization.
+     * hotValues == null: not collected (e.g. full analyze, or a sample 
analyze that used
+     * the linear estimator). Do NOT use for optimization.
      * hotValues != null && hotValues.isEmpty(): collected but no hot values 
(not skewed).
      * hotValues != null && !hotValues.isEmpty(): collected with hot values.
      */
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/statistics/OlapAnalysisTask.java 
b/fe/fe-core/src/main/java/org/apache/doris/statistics/OlapAnalysisTask.java
index 0e856c9787e..2712ea4a245 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/statistics/OlapAnalysisTask.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/statistics/OlapAnalysisTask.java
@@ -118,19 +118,20 @@ public class OlapAnalysisTask extends BaseAnalysisTask {
         Map<String, String> params = buildSqlParams();
         params.put("min", StatisticsUtil.quote(min));
         params.put("max", StatisticsUtil.quote(max));
-        params.put("hotValueCollectCount", 
String.valueOf(SessionVariable.getHotValueCollectCount()));
         long tableRowCount = info.indexId == -1
                 ? tbl.getRowCount()
                 : ((OlapTable) tbl).getRowCountForIndex(info.indexId, false);
         SampleCollectInfo collectInfo = getSampleCollectInfo(tableRowCount);
         getSampleParams(params, tableRowCount, collectInfo);
-        StringSubstitutor stringSubstitutor = new StringSubstitutor(params);
-        String sql;
+        String template = LINEAR_ANALYZE_TEMPLATE;
         if (collectInfo.algorithm == AnalyzeSampleAlgorithm.DUJ1) {
-            sql = stringSubstitutor.replace(DUJ1_ANALYZE_TEMPLATE);
-        } else {
-            sql = stringSubstitutor.replace(LINEAR_ANALYZE_TEMPLATE);
+            // DUJ1 is the only sample algorithm that collects hot values, and 
it derives them
+            // from the grouped sample it already builds for the NDV estimate, 
so only it needs
+            // the top-N count.
+            params.put("hotValueCollectCount", 
String.valueOf(SessionVariable.getHotValueCollectCount()));
+            template = DUJ1_ANALYZE_TEMPLATE;
         }
+        String sql = new StringSubstitutor(params).replace(template);
         LOG.info("Analyze param: algorithm {}, partitionColumnTooMany {}, 
keyColumnTooMany {}",
                 collectInfo.algorithm, partitionColumnSampleTooManyRows, 
keyColumnSampleTooManyRows);
         LOG.debug(sql);
@@ -306,7 +307,6 @@ public class OlapAnalysisTask extends BaseAnalysisTask {
         params.put("rowCount", String.valueOf(tableRowCount));
         params.put("type", col.getType().toString());
         params.put("limit", "");
-        params.put("subStringColName", getStringTypeColName(col));
 
         // For agg table and mor unique table, set PREAGGOPEN preAggHint.
         if (((OlapTable) tbl).getKeysType().equals(KeysType.AGG_KEYS)
@@ -356,11 +356,13 @@ public class OlapAnalysisTask extends BaseAnalysisTask {
     protected void setSampleParamsByAlgorithm(Map<String, String> params, long 
tableRowCount,
             AnalyzeSampleAlgorithm algorithm) {
         if (algorithm == AnalyzeSampleAlgorithm.DUJ1) {
+            // DUJ1 is the only sample algorithm that collects hot values: it 
derives them from
+            // the grouped sample it already builds for the NDV estimate below.
+            params.put("subStringColName", getStringTypeColName(col));
             params.put("ndvFunction", 
getNdvFunction(String.valueOf(tableRowCount)));
             params.put("dataSizeFunction", getDataSizeFunction(col, true));
             params.put("rowCount2", "(SELECT SUM(`count`) FROM cte1 WHERE 
`col_value` IS NOT NULL)");
         } else {
-            params.put("rowCount2", "(SELECT COUNT(1) FROM cte1 WHERE 
`${colName}` IS NOT NULL)");
             // For single unique key, use count as ndv.
             if (isSingleUniqueKey()) {
                 params.put("ndvFunction", String.valueOf(tableRowCount));
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/statistics/OlapAnalysisTaskTest.java
 
b/fe/fe-core/src/test/java/org/apache/doris/statistics/OlapAnalysisTaskTest.java
index b63816348b4..55d50597ff8 100644
--- 
a/fe/fe-core/src/test/java/org/apache/doris/statistics/OlapAnalysisTaskTest.java
+++ 
b/fe/fe-core/src/test/java/org/apache/doris/statistics/OlapAnalysisTaskTest.java
@@ -159,13 +159,8 @@ public class OlapAnalysisTaskTest {
                         + "ROUND(SUM(CASE WHEN `null` IS NULL THEN 1 ELSE 0 
END) * ${scaleFactor}) AS `null_count`, "
                         + "SUBSTRING(CAST('1' AS STRING), 1, 1024) AS `min`, "
                         + "SUBSTRING(CAST('2' AS STRING), 1, 1024) AS `max`, "
-                        + "COUNT(1) * 4 * ${scaleFactor} AS `data_size`, NOW() 
FROM cte1), "
-                        + "cte3 AS (SELECT 
IFNULL(GROUP_CONCAT(CONCAT(REPLACE(REPLACE(t.`column_key`, "
-                        + "\":\", \"\\\\:\"), \";\", \"\\\\;\"), \" :\", 
ROUND(t.`count` / ${rowCount2}, 2)), "
-                        + "\" ;\"), '') as `hot_value` FROM (SELECT 
${subStringColName} as `hash_value`, "
-                        + "MAX(`null`) as `column_key`, COUNT(1) AS `count` 
FROM cte1 "
-                        + "WHERE `null` IS NOT NULL GROUP BY `hash_value` 
ORDER BY `count` DESC LIMIT 10) t) "
-                        + "SELECT * FROM cte2 CROSS JOIN cte3", sql);
+                        + "COUNT(1) * 4 * ${scaleFactor} AS `data_size`, NOW() 
AS `update_time`, "
+                        + "null as `hot_value` FROM cte1) SELECT * FROM cte2", 
sql);
             }
         };
 
@@ -384,8 +379,9 @@ public class OlapAnalysisTaskTest {
                 new 
OlapAnalysisTask.SampleCollectInfo(AnalyzeSampleAlgorithm.FULL, null));
         Assertions.assertEquals("1", params.get("scaleFactor"));
         Assertions.assertEquals("", params.get("sampleHints"));
-        Assertions.assertEquals("(SELECT COUNT(1) FROM cte1 WHERE `${colName}` 
IS NOT NULL)",
-                params.get("rowCount2"));
+        // The linear estimator does not collect hot values, so it fills no 
hot value param.
+        Assertions.assertNull(params.get("rowCount2"));
+        Assertions.assertNull(params.get("subStringColName"));
         Assertions.assertEquals("ROUND(NDV(`${colName}`) * ${scaleFactor})", 
params.get("ndvFunction"));
         Assertions.assertNull(params.get("preAggHint"));
         Assertions.assertEquals("COUNT(1)", params.get("rowCount"));
@@ -396,8 +392,8 @@ public class OlapAnalysisTaskTest {
                 new 
OlapAnalysisTask.SampleCollectInfo(AnalyzeSampleAlgorithm.LINEAR,
                         Pair.of(Lists.newArrayList(1L, 2L), 100L)));
         Assertions.assertEquals("TABLET(1, 2)", params.get("sampleHints"));
-        Assertions.assertEquals("(SELECT COUNT(1) FROM cte1 WHERE `${colName}` 
IS NOT NULL)",
-                params.get("rowCount2"));
+        Assertions.assertNull(params.get("rowCount2"));
+        Assertions.assertNull(params.get("subStringColName"));
         Assertions.assertEquals("ROUND(NDV(`${colName}`) * ${scaleFactor})", 
params.get("ndvFunction"));
         params.clear();
 
@@ -410,6 +406,7 @@ public class OlapAnalysisTaskTest {
         Assertions.assertEquals("TABLET(1, 2)", params.get("sampleHints"));
         Assertions.assertEquals("(SELECT SUM(`count`) FROM cte1 WHERE 
`col_value` IS NOT NULL)",
                 params.get("rowCount2"));
+        Assertions.assertEquals("`${colName}`", 
params.get("subStringColName"));
         
Assertions.assertTrue(params.get("ndvFunction").contains("`t1`.`col_value`"),
                 "DUJ1 ndvFunction must reference cte1 output, got: " + 
params.get("ndvFunction"));
         params.clear();
diff --git 
a/regression-test/data/nereids_rules_p0/agg_strategy/physical_agg_regulator.out 
b/regression-test/data/nereids_rules_p0/agg_strategy/physical_agg_regulator.out
index a33a83f01e0..800cd8b556b 100644
--- 
a/regression-test/data/nereids_rules_p0/agg_strategy/physical_agg_regulator.out
+++ 
b/regression-test/data/nereids_rules_p0/agg_strategy/physical_agg_regulator.out
@@ -15,9 +15,7 @@ PhysicalCteAnchor ( cteId=CTEId#0 )
 --------hashAgg[GLOBAL]
 ----------hashAgg[GLOBAL]
 ------------PhysicalDistribute[DistributionSpecHash]
---------------hashAgg[LOCAL]
-----------------PhysicalDistribute[DistributionSpecExecutionAny]
-------------------PhysicalCteConsumer ( cteId=CTEId#0 )
+--------------PhysicalCteConsumer ( cteId=CTEId#0 )
 
 -- !not_skew --
 PhysicalCteAnchor ( cteId=CTEId#0 )
diff --git 
a/regression-test/suites/nereids_p0/stats/col_stats/hot_value_analyze_sync.groovy
 
b/regression-test/suites/nereids_p0/stats/col_stats/hot_value_analyze_sync.groovy
index 39c43134ab7..8ebc437890e 100644
--- 
a/regression-test/suites/nereids_p0/stats/col_stats/hot_value_analyze_sync.groovy
+++ 
b/regression-test/suites/nereids_p0/stats/col_stats/hot_value_analyze_sync.groovy
@@ -49,10 +49,16 @@ suite('hot_value_analyze_sync') {
     String realDb = context.config.getDbNameByFile(context.file)
     sql """
     drop table if exists t1025;
-    create table t1025(a_1 int, b_5 int, c_10 int, d_1025 int) distributed by 
hash(c_10) properties('replication_num'='1');
-    insert into t1025 select 1, number%5 , number%10, number from 
numbers("number"="100");
+    create table t1025(a_1 int, b_5 int, c_10 int, d_1025 int) distributed by 
hash(c_10) buckets 1 properties('replication_num'='1');
+    insert into t1025 select 1, number%5 , number%10, number from 
numbers("number"="10000");
     """
-    wait_row_count_reported(realDb, "t1025", 0, 4, "100")
+    wait_row_count_reported(realDb, "t1025", 0, 4, "10000")
+    // One bucket, so sample analyze is guaranteed to sample instead of 
falling back to a full scan:
+    // getSampleCollectInfo falls back when the sample request exceeds the 
table, or when the picked
+    // tablets hold fewer rows than requested, and both fallbacks use the 
linear estimator for every
+    // column, which does not collect hot value (`null as hot_value`). d_1025 
is not the distribution
+    // column, so a real sample analyzes it with the DUJ1 estimator, which 
does collect hot value -
+    // the property this suite exists to check.
     sql "analyze table t1025 with sample rows 4000 with sync;"
     def result = sql "show column cached stats t1025"
     log.info(result.toString())
diff --git 
a/regression-test/suites/nereids_rules_p0/agg_strategy/physical_agg_regulator.groovy
 
b/regression-test/suites/nereids_rules_p0/agg_strategy/physical_agg_regulator.groovy
index 7b9f2c04f9a..868eb044ce8 100644
--- 
a/regression-test/suites/nereids_rules_p0/agg_strategy/physical_agg_regulator.groovy
+++ 
b/regression-test/suites/nereids_rules_p0/agg_strategy/physical_agg_regulator.groovy
@@ -22,6 +22,11 @@ suite("physical_agg_regulator") {
     set enable_parallel_result_sink=false;
     set be_number_for_test=1;
     """
+    // A sample request larger than the table falls back to a full scan with 
the linear estimator,
+    // which does not collect hot value. branch-4.1 has no `WITH HOT VALUE` 
clause to ask for hot
+    // values explicitly, and this table is distributed by a single column, so 
every sample analyze
+    // of it uses the linear estimator. The expected plan therefore reflects 
the no-hot-value
+    // behaviour of the linear estimator.
     multi_sql """
     analyze table t1025_skew5000 with sample rows 7000 with sync;
     --drop cached stats t1025;
@@ -31,6 +36,7 @@ suite("physical_agg_regulator") {
     select count(distinct a_1), count(distinct b_5) from t1025_skew5000 group 
by d_1025;"""
 
 
+    // Same reason as above: no hot values are collected on this path in 
branch-4.1.
     multi_sql """
     analyze table t1025 with sample rows 4000 with sync;
     --drop cached stats t1025;
diff --git a/regression-test/suites/statistics/test_hot_value.groovy 
b/regression-test/suites/statistics/test_hot_value.groovy
index b2d6de2be52..0baa7bc37ac 100644
--- a/regression-test/suites/statistics/test_hot_value.groovy
+++ b/regression-test/suites/statistics/test_hot_value.groovy
@@ -109,6 +109,9 @@ suite("test_hot_value") {
     logger.info("result " + result)
     assertEquals(1, result.size())
     assertEquals("10000.0", result[0][2])
+    // key1 is the single distribution column, so a real sample analyzes it 
with the linear
+    // estimator, which does not collect hot_value.
+    assertEquals("null", String.valueOf(result[0][17]))
     result = sql """show column stats test1(value1)"""
     logger.info("1. result " + result)
     assertEquals(1, result.size())
@@ -128,29 +131,24 @@ suite("test_hot_value") {
     assertTrue(hotValues[1] == "'1':0.5" || hotValues[1] == "'0':0.5")
 
     sql """drop stats test1"""
+    // The requested sample rows are larger than the table, so sample analyze 
falls back to a
+    // full scan with the linear estimator, which does not collect hot_value.
     sql """analyze table test1 with sample rows 40000 with sync"""
     result = sql """show column stats test1(key1)"""
     logger.info("result " + result)
     assertEquals(1, result.size())
     assertEquals("10000.0", result[0][2])
+    assertEquals("null", String.valueOf(result[0][17]))
     result = sql """show column stats test1(value1)"""
     logger.info("2. result " + result)
-    logger.info("result.size()" + result.size())
     assertEquals(1, result.size())
-    logger.info("result[0][2] " + result[0][2])
     assertEquals("10000.0", result[0][2])
-    hotValues = result[0][17].split(";")
-    assertEquals(2, hotValues.length)
-    assertTrue(hotValues[0] == "'1':0.5" || hotValues[0] == "'0':0.5")
-    assertTrue(hotValues[1] == "'1':0.5" || hotValues[1] == "'0':0.5")
+    assertEquals("null", String.valueOf(result[0][17]))
     result = sql """show column cached stats test1(value1)"""
     logger.info("result " + result)
     assertEquals(1, result.size())
     assertEquals("10000.0", result[0][2])
-    hotValues = result[0][17].split(";")
-    assertEquals(2, hotValues.length)
-    assertTrue(hotValues[0] == "'1':0.5" || hotValues[0] == "'0':0.5")
-    assertTrue(hotValues[1] == "'1':0.5" || hotValues[1] == "'0':0.5")
+    assertEquals("null", String.valueOf(result[0][17]))
 
     sql """alter table test1 modify column value1 set stats 
('row_count'='100.0', 'ndv'='5.0', 'num_nulls'='0.0', 'data_size'='34.0', 
'min_value'='AFRICA', 'max_value'='MIDDLE EAST', 'hot_values'='aaa :0.8');"""
     result = sql """show column stats test1(value1)"""
@@ -195,13 +193,15 @@ suite("test_hot_value") {
     assertEquals("' : ;a':1.0", result[0][17])
 
     sql """drop stats test2"""
+    // As for test1 above, the requested sample rows are larger than the 
table, so sample analyze
+    // falls back to a full scan with the linear estimator, which does not 
collect hot_value.
     sql """analyze table test2 with sample rows 4000000 with sync"""
     result = sql """show column stats test2(value1)"""
     assertEquals(1, result.size())
-    assertEquals("' : ;a':1.0", result[0][17])
-    result = sql """show column cached stats test2(value1)"""   
+    assertEquals("null", String.valueOf(result[0][17]))
+    result = sql """show column cached stats test2(value1)"""
     assertEquals(1, result.size())
-    assertEquals("' : ;a':1.0", result[0][17])
+    assertEquals("null", String.valueOf(result[0][17]))
 
     sql """drop database if exists test_hot_value"""
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to