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]