Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[Bug] Fix invalid validation for sampled column statistics with ndv=0 and non-null min/max#64206

Open
MilanTyagi2004 wants to merge 3 commits into
apache:masterfrom
MilanTyagi2004:master
Open

[Bug] Fix invalid validation for sampled column statistics with ndv=0 and non-null min/max#64206
MilanTyagi2004 wants to merge 3 commits into
apache:masterfrom
MilanTyagi2004:master

Conversation

@MilanTyagi2004

Copy link
Copy Markdown

What problem does this PR solve?

Issue Number: close #64122

Problem Summary:

ColStatsData.isValid() applies a validation rule that assumes all statistics originate from the same source. However, during SAMPLE ANALYZE this assumption does not always hold:

  • min/max values may come from a full-table scan.
  • ndv may be estimated from sampled data.
  • nullCount may be a scaled estimate and therefore differ from count.

As a result, sampled column statistics can be incorrectly rejected when:

ndv == 0
&& (!isNull(minLit) || !isNull(maxLit))
&& nullCount != count

This PR introduces sample-aware handling by adding an isSample flag to ColStatsData. For sampled statistics, when ndv == 0 but non-null min/max values exist, ndv is normalized to 1 before validation. This prevents valid sampled statistics from being rejected while preserving the existing validation behavior for full analyze jobs.

Release note

None

Check List (For Author)

  • Test

    • Unit Test
  • Behavior changed:

    • No.
  • Does this need documentation?

    • No.

Test Details

Added unit tests in ColStatsDataTest covering:

  1. Full analyze statistics:

    • ndv = 0
    • non-null min/max
    • nullCount != count

    Expected result: validation fails.

  2. Sample analyze statistics:

    • ndv = 0
    • non-null min/max
    • nullCount != count

    Expected result:

    • ndv is normalized to 1
    • validation succeeds.

Issue Number: close apache#64122

Problem Summary: Under sample analysis, count and nullCount are scaled/rounded estimates and can differ, while min/max are retrieved from full scans. This mismatch causes `ColStatsData.isValid()` to reject valid statistics because `ndv == 0 && (!isNull(minLit) || !isNull(maxLit)) && nullCount != count`. This PR fixes the issue by passing `isSample` to clamp `ndv` to 1.

- Test: Unit Test (ColStatsDataTest)
- Behavior changed: No
- Does this need documentation: No
@hello-stephen

Copy link
Copy Markdown
Contributor

Thank you for your contribution to Apache Doris.
Don't know what should be done next? See How to process your PR.

Please clearly describe your PR:

  1. What problem was fixed (it's best to include specific error reporting information). How it was fixed.
  2. Which behaviors were modified. What was the previous behavior, what is it now, why was it modified, and what possible impacts might there be.
  3. What features were added. Why was this function added?
  4. Which code was refactored and why was this part of the code refactored?
  5. Which functions were optimized and what is the difference before and after the optimization?

@MilanTyagi2004

Copy link
Copy Markdown
Author

run buildall

@MilanTyagi2004

Copy link
Copy Markdown
Author

The TeamCity compile failure appears unrelated to the changes in this PR.

The build fails while downloading sccache during Rust dependency setup:

gzip: stdin: not in gzip format

This causes sccache to be unavailable and the Rust build to fail before compilation of the actual changes.

Could a maintainer please check or rerun the CI?

Thank you.

@englefly

englefly commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

这个 pr 对应的场景是 ndv 不可用,但 min/max/num_nulls 可用. 在这种场景下希望继续使用 min/max/num_nulls, 所以将 ndv 设置为 1. 是吗?
ndv 是最重要的一个列统计信息,如果设置为 1, 统计信息推导(StatsCalculator)必须做相应的改动,否则会产生一些比较极端的情况,导致 plan 劣化

@MilanTyagi2004

MilanTyagi2004 commented Jun 8, 2026

Copy link
Copy Markdown
Author

感谢反馈。

当前实现是参考 issue 讨论中提到的方向:当 sampled statistics 中 ndv=0,但 min/max 表明存在非 NULL 值时,将 ndv 从 0 归一化为 1,从而保留 min/max 和 nullCount 信息,而不是直接丢弃整条列统计信息。

不过我理解您的担忧:将 ndv 设置为 1 可能会影响后续 StatsCalculator 的统计推导。

您更倾向于哪种方案:

  1. 保持 ndv=0,并针对 sampled statistics 调整验证逻辑(包括 StatsCalculator.checkNdvValidation);
  2. 继续使用 ndv=1 的归一化方案,并在 StatsCalculator 中补充相应处理。

我可以按照您建议的方向修改。

@hello-stephen

Copy link
Copy Markdown
Contributor

FE Regression Coverage Report

Increment line coverage 2.96% (4/135) 🎉
Increment coverage report
Complete coverage report

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-H: Total hot run time: 28870 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpch-tools
Tpch sf100 test result on commit 04c6feca1723aef80b941d56ad9986743bbe3933, data reload: false

------ Round 1 ----------------------------------
orders	Doris	NULL	NULL	0	0	0	NULL	0	NULL	NULL	2023-12-26 18:27:23	2023-12-26 18:42:55	NULL	utf-8	NULL	NULL	
============================================
q1	17662	3968	4004	3968
q2	q3	10754	1415	788	788
q4	4687	482	344	344
q5	7603	875	576	576
q6	184	170	137	137
q7	770	837	633	633
q8	9387	1634	1552	1552
q9	5710	4507	4489	4489
q10	6744	1803	1533	1533
q11	439	276	254	254
q12	626	432	288	288
q13	18116	3359	2782	2782
q14	270	261	239	239
q15	q16	824	782	714	714
q17	984	875	1034	875
q18	6966	5794	5507	5507
q19	1341	1219	1025	1025
q20	520	409	271	271
q21	6258	2821	2578	2578
q22	452	369	317	317
Total cold run time: 100297 ms
Total hot run time: 28870 ms

----- Round 2, with runtime_filter_mode=off -----
orders	Doris	NULL	NULL	150000000	42	6422171781	NULL	22778155	NULL	NULL	2023-12-26 18:27:23	2023-12-26 18:42:55	NULL	utf-8	NULL	NULL	
============================================
q1	5052	4885	4798	4798
q2	q3	4926	5314	4653	4653
q4	2126	2166	1354	1354
q5	4765	4818	4635	4635
q6	229	181	134	134
q7	1952	1825	1532	1532
q8	2406	2117	2094	2094
q9	7977	7638	7414	7414
q10	4719	4631	4253	4253
q11	532	380	347	347
q12	720	740	522	522
q13	3055	3334	2797	2797
q14	277	281	254	254
q15	q16	679	697	603	603
q17	1270	1244	1243	1243
q18	7344	6756	6700	6700
q19	1145	1070	1075	1070
q20	2228	2229	1934	1934
q21	5247	4516	4421	4421
q22	497	450	397	397
Total cold run time: 57146 ms
Total hot run time: 51155 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-DS: Total hot run time: 169071 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpcds-tools
TPC-DS sf100 test result on commit 04c6feca1723aef80b941d56ad9986743bbe3933, data reload: false

query5	4312	625	482	482
query6	452	202	186	186
query7	4866	558	305	305
query8	374	220	202	202
query9	8756	4012	4074	4012
query10	478	311	264	264
query11	5962	2349	2195	2195
query12	167	103	97	97
query13	1282	647	438	438
query14	6406	5397	5069	5069
query14_1	4416	4417	4395	4395
query15	208	200	183	183
query16	978	472	439	439
query17	1130	716	607	607
query18	2594	491	366	366
query19	208	193	154	154
query20	120	110	109	109
query21	223	144	118	118
query22	13649	13593	13454	13454
query23	17325	16459	16134	16134
query23_1	16223	16330	16260	16260
query24	7579	1812	1317	1317
query24_1	1348	1317	1288	1288
query25	593	475	414	414
query26	1336	298	167	167
query27	2661	525	337	337
query28	4497	2037	2012	2012
query29	1099	637	520	520
query30	308	234	200	200
query31	1126	1073	964	964
query32	111	64	64	64
query33	532	329	304	304
query34	1166	1148	659	659
query35	752	797	681	681
query36	1338	1369	1240	1240
query37	165	112	97	97
query38	3186	3168	3068	3068
query39	923	947	877	877
query39_1	907	869	862	862
query40	219	124	103	103
query41	69	62	62	62
query42	95	95	92	92
query43	331	327	283	283
query44	
query45	196	182	182	182
query46	1067	1213	708	708
query47	2359	2374	2219	2219
query48	401	420	289	289
query49	627	468	353	353
query50	1005	352	257	257
query51	4313	4269	4265	4265
query52	90	92	79	79
query53	248	280	195	195
query54	269	222	197	197
query55	82	77	70	70
query56	253	222	209	209
query57	1417	1408	1331	1331
query58	239	214	217	214
query59	1570	1631	1403	1403
query60	282	247	233	233
query61	168	161	159	159
query62	722	652	591	591
query63	232	185	191	185
query64	2568	812	641	641
query65	
query66	1779	480	342	342
query67	29774	29688	29533	29533
query68	
query69	429	300	257	257
query70	962	952	964	952
query71	310	220	225	220
query72	2887	2643	2444	2444
query73	881	730	450	450
query74	5153	4941	4857	4857
query75	2606	2575	2227	2227
query76	2338	1169	777	777
query77	362	382	284	284
query78	12400	12321	11750	11750
query79	1222	1089	764	764
query80	531	471	403	403
query81	449	275	244	244
query82	235	154	128	128
query83	270	275	251	251
query84	
query85	839	545	437	437
query86	331	303	279	279
query87	3366	3332	3199	3199
query88	3663	2730	2725	2725
query89	404	391	345	345
query90	2181	184	182	182
query91	183	168	137	137
query92	65	60	60	60
query93	1479	1470	959	959
query94	544	354	324	324
query95	694	472	340	340
query96	1009	857	353	353
query97	2686	2680	2583	2583
query98	211	207	201	201
query99	1151	1170	1029	1029
Total cold run time: 250081 ms
Total hot run time: 169071 ms

@liutang123

Copy link
Copy Markdown
Contributor

这个 pr 对应的场景是 ndv 不可用,但 min/max/num_nulls 可用. 在这种场景下希望继续使用 min/max/num_nulls, 所以将 ndv 设置为 1. 是吗? ndv 是最重要的一个列统计信息,如果设置为 1, 统计信息推导(StatsCalculator)必须做相应的改动,否则会产生一些比较极端的情况,导致 plan 劣化

You can see this issue: #64122.
This issue can cause serious problem.

…mple analyze success

### What problem does this PR solve?

Issue Number: close apache#64122

Related PR: apache#64206

Problem Summary: SAMPLE ANALYZE fails because ColStatsData.isValid() rejects statistics where ndv = 0, min/max is non-null, and nullCount != count. To fix this, we allow statistics collection and persistence to succeed without ndv normalization. When statistics are loaded later, they are detected as suspicious and treated as UNKNOWN ColumnStatistic by the optimizer.

### Release note

None

### Check List (For Author)

- Test:
    - Unit Test (ColStatsDataTest)
- Behavior changed: Yes (Suspicious statistics with ndv=0 and non-null min/max are now persisted instead of raising exceptions, and treated as UNKNOWN by Nereids optimizer)
- Does this need documentation: No
@MilanTyagi2004

Copy link
Copy Markdown
Author

run buildall

@MilanTyagi2004

Copy link
Copy Markdown
Author

The failing checks appear unrelated to the statistics changes in this PR.

FE UT failure reports parser errors such as:

  • mismatched input '->'
  • no viable alternative at input 'super::'

which do not correspond to any code introduced by this PR.

The Performance job also appears to fail during environment cleanup/startup rather than statistics execution.

I have reviewed the modified files in this PR and do not see any introduced lambda (->) or method reference (::) syntax.

Could a maintainer help verify whether these failures are caused by an infrastructure or upstream issue, or rerun the checks after rebasing onto the latest master?

@morrySnow

Copy link
Copy Markdown
Contributor

@MilanTyagi2004 do you still work on this issue?

@yujun777

yujun777 commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.10.1:compile (default-compile) on project fe-core: Compilation failure: Compilation failure: [22:03:46 ](http://43.132.222.7:8111/buildConfiguration/Doris_DorisCompile_Compile/971150?expandBuildDeploymentsSection=false&hideTestsFromDependencies=false&hideProblemsFromDependencies=false&expandPull+Request+Details=true&expandBuildProblemsSection=true&showLog=971150_20131_20131&logFilter=debug&logView=flowAware) [ERROR] /root/doris/fe/fe-core/src/main/java/org/apache/doris/statistics/ColumnStatistic.java:[186,16] variable min is already defined in method fromResultRow(org.apache.doris.statistics.ResultRow) [22:03:46 ](http://43.132.222.7:8111/buildConfiguration/Doris_DorisCompile_Compile/971150?expandBuildDeploymentsSection=false&hideTestsFromDependencies=false&hideProblemsFromDependencies=false&expandPull+Request+Details=true&expandBuildProblemsSection=true&showLog=971150_20132_20132&logFilter=debug&logView=flowAware) [ERROR] /root/doris/fe/fe-core/src/main/java/org/apache/doris/statistics/ColumnStatistic.java:[187,16] variable max is already defined in method fromResultRow(org.apache.doris.statistics.ResultRow) [22:03:46 ](http://43.132.222.7:8111/buildConfiguration/Doris_DorisCompile_Compile/971150?expandBuildDeploymentsSection=false&hideTestsFromDependencies=false&hideProblemsFromDependencies=false&expandPull+Request+Details=true&expandBuildProblemsSection=true&showLog=971150_20133_20133&logFilter=debug&logView=flowAware) [ERROR] -> [Help 1]

can you open the compile pipeline log ? PR had compile failed

@MilanTyagi2004

Copy link
Copy Markdown
Author

apology for the delay
my university exam is going on.
@morrySnow Yes i am still working on this.

@morrySnow

Copy link
Copy Markdown
Contributor

apology for the delay my university exam is going on. @morrySnow Yes i am still working on this.

@MilanTyagi2004, I'm very glad to hear that you will continue with this work. When can you start working on it again? This is a very important repair and we hope to complete it as soon as possible.

@MilanTyagi2004

Copy link
Copy Markdown
Author

apology for the delay my university exam is going on. @morrySnow Yes i am still working on this.

@MilanTyagi2004, I'm very glad to hear that you will continue with this work. When can you start working on it again? This is a very important repair and we hope to complete it as soon as possible.

I will start working today on this issue and present the best solution in next upcoming days

### What problem does this PR solve?

Issue Number: close apache#64122, close apache#64206

Problem Summary:
In PR apache#50574, logic was added to StatsCalculator to treat statistics with ndv=0, min/max not null, and nullCount == count as UNKNOWN (which represents sampling an all-null tablet).
However, this check was only implemented inside a single overload of StatsCalculator#getColumnStatistic, which is bypassed by scan optimization nodes (like OlapScan, HiveScan, and partition-stats merge). As a result, suspicious statistics under the nullCount == count case were not treated as UNKNOWN during CBO estimation.
We unify the validation rules into ColumnStatistic.isSuspiciousStats(...) by removing the `nullCount != count` check. This ensures that any suspicious statistics (ndv == 0 but min/max not null) are automatically deserialized as ColumnStatistic.UNKNOWN at the cache level, making it consistent for all optimizer scan paths. Added unit tests to ColStatsDataTest to cover the nullCount == count case.

### Release note

None

### Check List (For Author)

- Test: Unit Test
    - Unit Test (ColStatsDataTest.java)
- Behavior changed: No
- Does this need documentation: No
@MilanTyagi2004

Copy link
Copy Markdown
Author

/review

@MilanTyagi2004

MilanTyagi2004 commented Jul 7, 2026

Copy link
Copy Markdown
Author

run buildall

@MilanTyagi2004

Copy link
Copy Markdown
Author

Hi @morrySnow,
could you please review it and failure of CI/CD is unrelated to my changes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] ColStatsData.isValid() falsely rejects sampled column statistics when a column is (almost) all NULL

6 participants