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 96f5891be84 branch-4.1: [fix](statistics) Use one algorithm decision
to pick both params and template in sample analyze #66578 (#66657)
96f5891be84 is described below
commit 96f5891be8457cd19e7c9d6c6fd0386a2f1170b2
Author: yujun <[email protected]>
AuthorDate: Wed Aug 12 10:12:22 2026 +0800
branch-4.1: [fix](statistics) Use one algorithm decision to pick both
params and template in sample analyze #66578 (#66657)
cherry-pick: #66578
---
.../apache/doris/statistics/BaseAnalysisTask.java | 15 ++
.../apache/doris/statistics/OlapAnalysisTask.java | 157 +++++++++++++--------
.../doris/statistics/OlapAnalysisTaskTest.java | 132 ++++++++++++++---
3 files changed, 224 insertions(+), 80 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 f382cb8350c..47a2cb98f05 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
@@ -65,6 +65,21 @@ public abstract class BaseAnalysisTask {
public static final long LIMIT_SIZE = 1024 * 1024 * 1024; // 1GB
public static final double LIMIT_FACTOR = 1.2;
+ /**
+ * The statistics collection algorithm chosen for a sampled analyze task.
It determines
+ * both the SQL template used to collect stats and the params rendered
into it, so callers
+ * must derive the template and the params from the same algorithm
decision.
+ */
+ public enum AnalyzeSampleAlgorithm {
+ // Full table scan without sampling, used when the table is small or
the sample
+ // tablets contain too few rows. Statistics are computed with the
LINEAR template.
+ FULL,
+ // Linear estimator, used for single unique key column / single
distribution column.
+ LINEAR,
+ // DUJ1 estimator, based on the PostgreSQL analyze algorithm.
+ DUJ1
+ }
+
/**
* Marker string embedded in {@code assert_true} inside statistics
collection SQL.
* When any row's string column length exceeds the configured limit, BE
throws an
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 bd0c5d94f12..0e856c9787e 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
@@ -68,7 +68,6 @@ public class OlapAnalysisTask extends BaseAnalysisTask {
private boolean keyColumnSampleTooManyRows = false;
private boolean partitionColumnSampleTooManyRows = false;
- private boolean scanFullTable = false;
private static final long MAXIMUM_SAMPLE_ROWS = 1_000_000_000;
public static final long NO_SKIP_TABLET_ID = -1;
@@ -123,16 +122,17 @@ public class OlapAnalysisTask extends BaseAnalysisTask {
long tableRowCount = info.indexId == -1
? tbl.getRowCount()
: ((OlapTable) tbl).getRowCountForIndex(info.indexId, false);
- getSampleParams(params, tableRowCount);
+ SampleCollectInfo collectInfo = getSampleCollectInfo(tableRowCount);
+ getSampleParams(params, tableRowCount, collectInfo);
StringSubstitutor stringSubstitutor = new StringSubstitutor(params);
String sql;
- if (useLinearAnalyzeTemplate()) {
- sql = stringSubstitutor.replace(LINEAR_ANALYZE_TEMPLATE);
- } else {
+ if (collectInfo.algorithm == AnalyzeSampleAlgorithm.DUJ1) {
sql = stringSubstitutor.replace(DUJ1_ANALYZE_TEMPLATE);
+ } else {
+ sql = stringSubstitutor.replace(LINEAR_ANALYZE_TEMPLATE);
}
- LOG.info("Analyze param: scanFullTable {}, partitionColumnTooMany {},
keyColumnTooMany {}",
- scanFullTable, partitionColumnSampleTooManyRows,
keyColumnSampleTooManyRows);
+ LOG.info("Analyze param: algorithm {}, partitionColumnTooMany {},
keyColumnTooMany {}",
+ collectInfo.algorithm, partitionColumnSampleTooManyRows,
keyColumnSampleTooManyRows);
LOG.debug(sql);
runQuery(sql);
}
@@ -234,9 +234,8 @@ public class OlapAnalysisTask extends BaseAnalysisTask {
LOG.info("Add large tablet {} in table {} back, with rows {}",
largeTabletId, tbl.getName(), largeTabletRows);
}
- if (selectedRows < targetSampleRows) {
- scanFullTable = true;
- } else if (forPartitionColumn && selectedRows > MAXIMUM_SAMPLE_ROWS) {
+ // If sampled rows are not enough, the caller falls back to a full
table scan.
+ if (forPartitionColumn && selectedRows > MAXIMUM_SAMPLE_ROWS) {
// If the selected tablets for partition column contain too many
rows, change to linear sample.
partitionColumnSampleTooManyRows = true;
sampleTabletIds.clear();
@@ -251,12 +250,58 @@ public class OlapAnalysisTask extends BaseAnalysisTask {
return Pair.of(sampleTabletIds, selectedRows);
}
+ /**
+ * Result of the sample analyze algorithm decision: the chosen algorithm
and, when
+ * sampling is actually performed, the picked tablets used to build the
{@code TABLET(...)}
+ * hint. Kept local to the sampling flow so the long-lived task holds no
sampling state.
+ */
+ protected static class SampleCollectInfo {
+ public final AnalyzeSampleAlgorithm algorithm;
+ public final Pair<List<Long>, Long> sampleTablets;
+
+ public SampleCollectInfo(AnalyzeSampleAlgorithm algorithm,
Pair<List<Long>, Long> sampleTablets) {
+ this.algorithm = algorithm;
+ this.sampleTablets = sampleTablets;
+ }
+ }
+
+ /**
+ * Decide which statistics algorithm to use and, when sampling is actually
performed,
+ * collect the sample tablets. Call this before
+ * {@link #getSampleParams(Map, long, SampleCollectInfo)} so the params
are always filled
+ * according to the algorithm used to pick the template.
+ */
+ protected SampleCollectInfo getSampleCollectInfo(long tableRowCount) {
+ // Debug point used by tests to force the DUJ1 algorithm. Check it
before the
+ // row-count based FULL decision so tests are not affected by BE row
count report
+ // timing (e.g. a small table whose row count is not fully reported
yet).
+ if (DebugPointUtil.isEnable("OlapAnalysisTask.useDUJ1Template")) {
+ return new SampleCollectInfo(AnalyzeSampleAlgorithm.DUJ1,
getSampleTablets());
+ }
+ long targetSampleRows = getSampleRows();
+ // If table row count is less than the target sample row count, simple
scan the full table.
+ if (tableRowCount <= targetSampleRows) {
+ return new SampleCollectInfo(AnalyzeSampleAlgorithm.FULL, null);
+ }
+ Pair<List<Long>, Long> sampleTablets = getSampleTablets();
+ if (sampleTablets.second < targetSampleRows) {
+ // Sampled tablets contain too few rows, fall back to a full table
scan.
+ return new SampleCollectInfo(AnalyzeSampleAlgorithm.FULL, null);
+ }
+ if (useLinearAnalyzeTemplate()) {
+ return new SampleCollectInfo(AnalyzeSampleAlgorithm.LINEAR,
sampleTablets);
+ }
+ return new SampleCollectInfo(AnalyzeSampleAlgorithm.DUJ1,
sampleTablets);
+ }
+
/**
* Get the sql params for this sample task.
* @param params Sql params to use in analyze task.
* @param tableRowCount BE reported table/index row count.
+ * @param info The analyze algorithm decision from {@link
#getSampleCollectInfo(long)}.
*/
- protected void getSampleParams(Map<String, String> params, long
tableRowCount) {
+ protected void getSampleParams(Map<String, String> params, long
tableRowCount,
+ SampleCollectInfo info) {
long targetSampleRows = getSampleRows();
params.put("rowCount", String.valueOf(tableRowCount));
params.put("type", col.getType().toString());
@@ -270,44 +315,51 @@ public class OlapAnalysisTask extends BaseAnalysisTask {
params.put("preAggHint", "/*+PREAGGOPEN*/");
}
- // If table row count is less than the target sample row count, simple
scan the full table.
- if (tableRowCount <= targetSampleRows) {
+ // If the algorithm is FULL (table too small or sampled rows not
enough), scan the full table.
+ if (info.algorithm == AnalyzeSampleAlgorithm.FULL) {
params.put("scaleFactor", "1");
params.put("sampleHints", "");
- params.put("ndvFunction", "ROUND(NDV(`${colName}`) *
${scaleFactor})");
// For full table scan, use COUNT(1) for table row count.
params.put("rowCount", "COUNT(1)");
- params.put("rowCount2", "(SELECT COUNT(1) FROM cte1 WHERE
`${colName}` IS NOT NULL)");
- scanFullTable = true;
- return;
- }
- Pair<List<Long>, Long> sampleTabletsInfo = getSampleTablets();
- String tabletStr = sampleTabletsInfo.first.stream()
- .map(Object::toString)
- .collect(Collectors.joining(", "));
- String sampleHints = scanFullTable ? "" : String.format("TABLET(%s)",
tabletStr);
- params.put("sampleHints", sampleHints);
- long selectedRows = sampleTabletsInfo.second;
- long finalScanRows = selectedRows;
- double scaleFactor = scanFullTable ? 1 : (double) tableRowCount /
finalScanRows;
- params.put("scaleFactor", String.valueOf(scaleFactor));
-
- // If the tablets to be sampled are too large, use limit to control
the rows to read, and re-calculate
- // the scaleFactor.
- if (needLimit()) {
- finalScanRows = Math.min(targetSampleRows, selectedRows);
- if (col.isKey() && keyColumnSampleTooManyRows) {
- finalScanRows = MAXIMUM_SAMPLE_ROWS;
- }
- // Empty table doesn't need to limit.
- if (finalScanRows > 0) {
- scaleFactor = (double) tableRowCount / finalScanRows;
- params.put("limit", "limit " + finalScanRows);
- params.put("scaleFactor", String.valueOf(scaleFactor));
+ } else {
+ String tabletStr = info.sampleTablets.first.stream()
+ .map(Object::toString)
+ .collect(Collectors.joining(", "));
+ params.put("sampleHints", String.format("TABLET(%s)", tabletStr));
+ long selectedRows = info.sampleTablets.second;
+ long finalScanRows = selectedRows;
+ double scaleFactor = (double) tableRowCount / finalScanRows;
+ params.put("scaleFactor", String.valueOf(scaleFactor));
+
+ // If the tablets to be sampled are too large, use limit to
control the rows to read, and re-calculate
+ // the scaleFactor.
+ if (needLimit()) {
+ finalScanRows = Math.min(targetSampleRows, selectedRows);
+ if (col.isKey() && keyColumnSampleTooManyRows) {
+ finalScanRows = MAXIMUM_SAMPLE_ROWS;
+ }
+ // Empty table doesn't need to limit.
+ if (finalScanRows > 0) {
+ scaleFactor = (double) tableRowCount / finalScanRows;
+ params.put("limit", "limit " + finalScanRows);
+ params.put("scaleFactor", String.valueOf(scaleFactor));
+ }
}
}
- // Set algorithm related params.
- if (useLinearAnalyzeTemplate()) {
+ setSampleParamsByAlgorithm(params, tableRowCount, info.algorithm);
+ }
+
+ /**
+ * Set the algorithm related params. Must be called with the same
algorithm that the
+ * caller uses to pick the template, so the params always match the
template.
+ */
+ protected void setSampleParamsByAlgorithm(Map<String, String> params, long
tableRowCount,
+ AnalyzeSampleAlgorithm algorithm) {
+ if (algorithm == AnalyzeSampleAlgorithm.DUJ1) {
+ 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()) {
@@ -315,10 +367,6 @@ public class OlapAnalysisTask extends BaseAnalysisTask {
} else {
params.put("ndvFunction", "ROUND(NDV(`${colName}`) *
${scaleFactor})");
}
- } else {
- 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)");
}
}
@@ -496,9 +544,6 @@ public class OlapAnalysisTask extends BaseAnalysisTask {
* @return Return true when need to limit.
*/
protected boolean needLimit() {
- if (scanFullTable) {
- return false;
- }
// Key column is sorted, use limit will cause the ndv not accurate
enough, so skip key columns.
if (col.isKey() && !keyColumnSampleTooManyRows) {
return false;
@@ -529,7 +574,7 @@ public class OlapAnalysisTask extends BaseAnalysisTask {
if (DebugPointUtil.isEnable("OlapAnalysisTask.useDUJ1Template")) {
return false;
}
- if (partitionColumnSampleTooManyRows || scanFullTable) {
+ if (partitionColumnSampleTooManyRows) {
return true;
}
if (isSingleUniqueKey()) {
@@ -582,14 +627,4 @@ public class OlapAnalysisTask extends BaseAnalysisTask {
public void setPartitionColumnSampleTooManyRows(boolean value) {
partitionColumnSampleTooManyRows = value;
}
-
- @VisibleForTesting
- public void setScanFullTable(boolean value) {
- scanFullTable = value;
- }
-
- @VisibleForTesting
- public boolean scanFullTable() {
- return scanFullTable;
- }
}
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 4d25654afb7..b63816348b4 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
@@ -39,9 +39,11 @@ import org.apache.doris.catalog.Type;
import org.apache.doris.common.AnalysisException;
import org.apache.doris.common.FeConstants;
import org.apache.doris.common.Pair;
+import org.apache.doris.common.util.DebugPointUtil;
import org.apache.doris.datasource.CatalogIf;
import org.apache.doris.statistics.AnalysisInfo.AnalysisMethod;
import org.apache.doris.statistics.AnalysisInfo.JobType;
+import org.apache.doris.statistics.BaseAnalysisTask.AnalyzeSampleAlgorithm;
import org.apache.doris.statistics.util.StatisticsUtil;
import org.apache.doris.thrift.TStorageMedium;
@@ -135,7 +137,13 @@ public class OlapAnalysisTaskTest {
}
@Mock
- void getSampleParams(Map<String, String> params, long
tableRowCount) {}
+ void getSampleParams(Map<String, String> params, long
tableRowCount, OlapAnalysisTask.SampleCollectInfo info) {}
+
+ @Mock
+ OlapAnalysisTask.SampleCollectInfo getSampleCollectInfo(long
tableRowCount) {
+ return new
OlapAnalysisTask.SampleCollectInfo(AnalyzeSampleAlgorithm.LINEAR,
+ Pair.of(Lists.newArrayList(1L, 2L), 100L));
+ }
@Mock
boolean useLinearAnalyzeTemplate() {
@@ -193,8 +201,9 @@ public class OlapAnalysisTaskTest {
}
@Mock
- boolean useLinearAnalyzeTemplate() {
- return false;
+ OlapAnalysisTask.SampleCollectInfo getSampleCollectInfo(long
tableRowCount) {
+ return new
OlapAnalysisTask.SampleCollectInfo(AnalyzeSampleAlgorithm.DUJ1,
+ Pair.of(Lists.newArrayList(1L, 2L), 100L));
}
};
olapAnalysisTask.doSample();
@@ -318,11 +327,6 @@ public class OlapAnalysisTaskTest {
task.setPartitionColumnSampleTooManyRows(true);
Assertions.assertTrue(task.useLinearAnalyzeTemplate());
- task.setPartitionColumnSampleTooManyRows(false);
- task.setScanFullTable(true);
- Assertions.assertTrue(task.useLinearAnalyzeTemplate());
-
- task.setScanFullTable(false);
task.setPartitionColumnSampleTooManyRows(false);
new MockUp<OlapAnalysisTask>() {
@Mock
@@ -360,6 +364,11 @@ public class OlapAnalysisTaskTest {
protected boolean useLinearAnalyzeTemplate() {
return false;
}
+
+ @Mock
+ protected boolean isSingleUniqueKey() {
+ return false;
+ }
};
new MockUp<OlapTable>() {
@@ -370,17 +379,39 @@ public class OlapAnalysisTaskTest {
};
task.col = new Column("testColumn", Type.INT, true, null, null, "");
task.setTable(new OlapTable());
- task.getSampleParams(params, 10);
- Assertions.assertTrue(task.scanFullTable());
+ // FULL algorithm: scan the full table and fill LINEAR-style params
(raw column reference).
+ task.getSampleParams(params, 10,
+ 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"));
Assertions.assertEquals("ROUND(NDV(`${colName}`) * ${scaleFactor})",
params.get("ndvFunction"));
Assertions.assertNull(params.get("preAggHint"));
Assertions.assertEquals("COUNT(1)", params.get("rowCount"));
params.clear();
- task.getSampleParams(params, 10000);
- Assertions.assertEquals("10000", params.get("rowCount"));
+ // LINEAR algorithm with sample tablets.
+ task.getSampleParams(params, 10000,
+ 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.assertEquals("ROUND(NDV(`${colName}`) * ${scaleFactor})",
params.get("ndvFunction"));
+ params.clear();
+
+ // DUJ1 algorithm with sample tablets: rowCount2 and ndvFunction must
reference the cte1
+ // output columns (col_value/count), not the raw column name,
otherwise the DUJ1 SQL
+ // fails with "Unknown column".
+ task.getSampleParams(params, 10000,
+ new
OlapAnalysisTask.SampleCollectInfo(AnalyzeSampleAlgorithm.DUJ1,
+ Pair.of(Lists.newArrayList(1L, 2L), 100L)));
+ 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.assertTrue(params.get("ndvFunction").contains("`t1`.`col_value`"),
+ "DUJ1 ndvFunction must reference cte1 output, got: " +
params.get("ndvFunction"));
params.clear();
new MockUp<OlapTable>() {
@@ -392,7 +423,9 @@ public class OlapAnalysisTaskTest {
task = new OlapAnalysisTask();
task.col = new Column("testColumn", Type.INT, false, null, null, "");
task.setTable(new OlapTable());
- task.getSampleParams(params, 1000);
+ task.getSampleParams(params, 1000,
+ new
OlapAnalysisTask.SampleCollectInfo(AnalyzeSampleAlgorithm.DUJ1,
+ Pair.of(Lists.newArrayList(1L, 2L), 100L)));
Assertions.assertEquals("10.0", params.get("scaleFactor"));
Assertions.assertEquals("TABLET(1, 2)", params.get("sampleHints"));
Assertions.assertEquals("SUM(`t1`.`count`) * COUNT(`t1`.`col_value`) /
(SUM(`t1`.`count`) - SUM(IF(`t1`.`count` = 1 and `t1`.`col_value` is not null,
1, 0)) + SUM(IF(`t1`.`count` = 1 and `t1`.`col_value` is not null, 1, 0)) *
SUM(`t1`.`count`) / 1000)", params.get("ndvFunction"));
@@ -415,7 +448,9 @@ public class OlapAnalysisTaskTest {
task = new OlapAnalysisTask();
task.col = new Column("testColumn", Type.INT, false, null, null, "");
task.setTable(new OlapTable());
- task.getSampleParams(params, 1000);
+ task.getSampleParams(params, 1000,
+ new
OlapAnalysisTask.SampleCollectInfo(AnalyzeSampleAlgorithm.DUJ1,
+ Pair.of(Lists.newArrayList(1L, 2L), 100L)));
Assertions.assertEquals("/*+PREAGGOPEN*/", params.get("preAggHint"));
params.clear();
@@ -428,7 +463,9 @@ public class OlapAnalysisTaskTest {
task = new OlapAnalysisTask();
task.col = new Column("testColumn", Type.INT, false, null, null, "");
task.setTable(new OlapTable());
- task.getSampleParams(params, 1000);
+ task.getSampleParams(params, 1000,
+ new
OlapAnalysisTask.SampleCollectInfo(AnalyzeSampleAlgorithm.DUJ1,
+ Pair.of(Lists.newArrayList(1L, 2L), 100L)));
Assertions.assertNull(params.get("preAggHint"));
params.clear();
@@ -447,7 +484,9 @@ public class OlapAnalysisTaskTest {
task = new OlapAnalysisTask();
task.col = new Column("test", PrimitiveType.INT);
task.setTable(new OlapTable());
- task.getSampleParams(params, 1000);
+ task.getSampleParams(params, 1000,
+ new
OlapAnalysisTask.SampleCollectInfo(AnalyzeSampleAlgorithm.LINEAR,
+ Pair.of(Lists.newArrayList(1L, 2L), 100L)));
Assertions.assertEquals("10.0", params.get("scaleFactor"));
Assertions.assertEquals("TABLET(1, 2)", params.get("sampleHints"));
Assertions.assertEquals("ROUND(NDV(`${colName}`) * ${scaleFactor})",
params.get("ndvFunction"));
@@ -462,7 +501,9 @@ public class OlapAnalysisTaskTest {
task = new OlapAnalysisTask();
task.col = new Column("test", PrimitiveType.INT);
task.setTable(new OlapTable());
- task.getSampleParams(params, 1000);
+ task.getSampleParams(params, 1000,
+ new
OlapAnalysisTask.SampleCollectInfo(AnalyzeSampleAlgorithm.LINEAR,
+ Pair.of(Lists.newArrayList(1L, 2L), 100L)));
Assertions.assertEquals("10.0", params.get("scaleFactor"));
Assertions.assertEquals("TABLET(1, 2)", params.get("sampleHints"));
Assertions.assertEquals("1000", params.get("ndvFunction"));
@@ -482,7 +523,9 @@ public class OlapAnalysisTaskTest {
task = new OlapAnalysisTask();
task.col = new Column("test", PrimitiveType.INT);
task.setTable(new OlapTable());
- task.getSampleParams(params, 1000);
+ task.getSampleParams(params, 1000,
+ new
OlapAnalysisTask.SampleCollectInfo(AnalyzeSampleAlgorithm.LINEAR,
+ Pair.of(Lists.newArrayList(1L, 2L), 100L)));
Assertions.assertEquals("20.0", params.get("scaleFactor"));
Assertions.assertEquals("TABLET(1, 2)", params.get("sampleHints"));
Assertions.assertEquals("1000", params.get("ndvFunction"));
@@ -494,13 +537,64 @@ public class OlapAnalysisTaskTest {
true, null, null, null);
task.setKeyColumnSampleTooManyRows(true);
task.setTable(new OlapTable());
- task.getSampleParams(params, 2000000000);
+ task.getSampleParams(params, 2000000000,
+ new
OlapAnalysisTask.SampleCollectInfo(AnalyzeSampleAlgorithm.LINEAR,
+ Pair.of(Lists.newArrayList(1L, 2L), 100L)));
Assertions.assertEquals("2.0", params.get("scaleFactor"));
Assertions.assertEquals("TABLET(1, 2)", params.get("sampleHints"));
Assertions.assertEquals("2000000000", params.get("ndvFunction"));
Assertions.assertEquals("limit 1000000000", params.get("limit"));
}
+ @Test
+ public void testGetSampleCollectInfo() {
+ final long[] sampleRows = {100L};
+ final Pair<List<Long>, Long>[] sampleTablets = new Pair[]
{Pair.of(Lists.newArrayList(1L, 2L), 100L)};
+ final boolean[] linearTemplate = {false};
+ new MockUp<OlapAnalysisTask>() {
+ @Mock
+ protected long getSampleRows() {
+ return sampleRows[0];
+ }
+
+ @Mock
+ protected Pair<List<Long>, Long> getSampleTablets() {
+ return sampleTablets[0];
+ }
+
+ @Mock
+ protected boolean useLinearAnalyzeTemplate() {
+ return linearTemplate[0];
+ }
+ };
+
+ OlapAnalysisTask task = new OlapAnalysisTask();
+ // tableRowCount <= sample rows -> full table scan.
+ OlapAnalysisTask.SampleCollectInfo info =
task.getSampleCollectInfo(10);
+ Assertions.assertEquals(AnalyzeSampleAlgorithm.FULL, info.algorithm);
+
+ // tableRowCount > sample rows -> sample tablets, and
useLinearAnalyzeTemplate decides.
+ linearTemplate[0] = true;
+ info = task.getSampleCollectInfo(10000);
+ Assertions.assertEquals(AnalyzeSampleAlgorithm.LINEAR, info.algorithm);
+
+ // sample tablets contain too few rows -> fall back to full table scan.
+ sampleTablets[0] = Pair.of(Lists.newArrayList(1L, 2L), 10L);
+ info = task.getSampleCollectInfo(10000);
+ Assertions.assertEquals(AnalyzeSampleAlgorithm.FULL, info.algorithm);
+ // Debug point useDUJ1Template forces DUJ1 even when the row count
would normally
+ // fall back to a full table scan, so tests are not affected by BE row
count timing.
+ new MockUp<DebugPointUtil>() {
+ @Mock
+ public boolean isEnable(String debugPointName) {
+ return true;
+ }
+ };
+ sampleTablets[0] = Pair.of(Lists.newArrayList(1L, 2L), 10L);
+ info = task.getSampleCollectInfo(10000);
+ Assertions.assertEquals(AnalyzeSampleAlgorithm.DUJ1, info.algorithm);
+ }
+
@Test
public void testGetSkipPartitionId(@Mocked OlapTable tableIf) throws
AnalysisException {
// test null partition list
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]