Skip to content

[fix](be) Count variant data in information_schema.column_data_sizes - #68444

Merged
eldenmoon merged 10 commits into
apache:masterfrom
eldenmoon:fix-variant-column-data-sizes
Oct 19, 2026
Merged

eldenmoon merged 10 commits into
apache:masterfrom
eldenmoon:fix-variant-column-data-sizes

Conversation

@eldenmoon

Copy link
Copy Markdown
Member

What problem does this PR solve?

Issue Number: None

Related PR: #56815

Problem Summary:

information_schema.column_data_sizes reports 0 for COMPRESSED_DATA_BYTES,
UNCOMPRESSED_DATA_BYTES and RAW_DATA_BYTES of every VARIANT column, so a
per-column size breakdown leaves the variant out and overstates the share of
the other columns. Reproduce on master with 200,000 rows whose js STRING
column and v VARIANT column hold the same JSON:

CREATE TABLE t_cds (id BIGINT, js STRING, v VARIANT) DUPLICATE KEY(id)
DISTRIBUTED BY HASH(id) BUCKETS 1 PROPERTIES ("replication_num" = "1");
INSERT INTO t_cds SELECT number,
    concat('{"a":', number, ',"b":"', repeat('y', 50), '"}'),
    parse_to_variant(concat('{"a":', number, ',"b":"', repeat('y', 50), '"}'))
FROM numbers("number" = "200000");
SELECT c.COLUMN_NAME, SUM(c.COMPRESSED_DATA_BYTES)
FROM information_schema.column_data_sizes c
JOIN information_schema.metadata_name_ids m ON c.TABLE_ID = m.TABLE_ID
WHERE m.TABLE_NAME = 't_cds' GROUP BY 1;
-- id 8214, js 823161, v 0 (still 0 after a full compaction)

The table reads the data page sizes that the segment writer stores in each
column meta of the segment footer. Two gaps drop the variant:

  1. VariantColumnWriter, VariantSubcolumnWriter and
    VariantDocCompactWriter return 0 (TODO) from get_raw_data_bytes(),
    get_total_uncompressed_data_pages_bytes() and
    get_total_compressed_data_pages_bytes(), although the variant data is
    written by their inner writers: the root, the materialized subcolumns and
    the sparse or doc value columns.
  2. Compaction writes variant subcolumns, sparse columns and doc value columns
    as columns of their own. Their metas have no unique id, so the scanner drops
    them; with external column meta (storage_format = "V3") the sparse and
    doc value metas are also embedded in the root variant meta, which the
    scanner never looks into.

Fix:

  • The variant writers sum the three counters over their inner writers, the
    same way the struct, array and map writers already do.
    ColumnWriter::DataBytesGetter names the getter that the variant writer
    layers pass down.
  • The scanner counts a column meta that has data bytes but no unique id to its
    parent variant column (from its column path info), adds the sparse and doc
    value metas embedded in a variant root meta, and takes COLUMN_TYPE from the
    schema column (a subcolumn meta carries the subcolumn's type). Nothing is
    counted twice: the inner metas of a variant writer carry no data bytes.

After the fix, the variant reports the size of all its data pages before and
after compaction, for inline and external column meta, in ordinary and doc
mode. Segments written before the fix keep their old numbers until compaction
rewrites them.

The segment footer now stores real data bytes on variant column metas instead
of 0, so the 29 checked-in golden Segment files of the 14 variant cases in
segment_flusher_format_test are regenerated (each grows by 2 to 4 bytes;
only those three counters of the variant metas differ). The other 59 golden
cases are byte-identical.

The footer raw_data_bytes of a variant root is also the first-batch hint of the
segment iterator's adaptive batch size predictor when a query reads the whole
variant column. It was 0 for variants; it now holds the variant's data for
segments written by a load and the root's data for compaction output. It only
affects the first batch, which is capped at the probe rows either way. Vertical
compaction's footer-based batch size estimate still skips variant columns; its
stale comment is updated.

Release note

Fix information_schema.column_data_sizes reporting 0 bytes for VARIANT columns. Data written before the fix reports the new sizes once compaction rewrites it.

Check List (For Author)

  • Test

    • Regression test
    • Unit Test
    • Manual test (add detailed scripts or steps below)
    • No need to test or manual test. Explain why:
      • This is a refactor/code format and no logic has been changed.
      • Previous test can cover this change.
      • No code files have been changed.
      • Other reason

    BE UT: the variant column writers report exactly the data page bytes they append to the segment file (ordinary and doc mode variant writers, extracted subcolumn writer, doc compact writer); the golden segment tests, variant, compaction and segment writer tests pass.

    Regression test test_query_sys_column_data_sizes_variant: ordinary and doc mode variants with V2 and V3 column meta, before and after full compaction. The data pages of all columns must lie within the rowsets' DATA_DISK_SIZE and cover more than half of it; they cover 91%-96%. Without counting the metas embedded in the variant root, the V3 tables drop to 35% and 11% after compaction; without resolving the parent unique id, the V2 tables drop to 3% and 2%.

  • Behavior changed:

    • No.
    • Yes. information_schema.column_data_sizes reports the data size of VARIANT columns instead of 0, and variant column metas in the segment footer store their data page bytes instead of 0.
  • Does this need documentation?

    • No.
    • Yes.

Check List (For Reviewer who merge this PR)

  • Confirm the release note
  • Confirm test cases
  • Confirm document
  • Add branch pick label

🤖 Generated with Claude Code

eldenmoon and others added 4 commits September 23, 2026 18:39
### What problem does this PR solve?

Issue Number: None

Related PR: apache#56815

Problem Summary:

The segment writer stores each column's data page bytes (compressed,
uncompressed and raw) in its footer meta, which
`information_schema.column_data_sizes` reads. `VariantColumnWriter`,
`VariantSubcolumnWriter` and `VariantDocCompactWriter` returned 0 (TODO) from
`get_raw_data_bytes()`, `get_total_uncompressed_data_pages_bytes()` and
`get_total_compressed_data_pages_bytes()`, so every VARIANT column reported 0
bytes although its data is written by inner writers: the root, the
materialized subcolumns and the sparse or doc value columns.

The variant writers now sum the three counters over their inner writers, the
same way the struct, array and map writers already do.
`ColumnWriter::DataBytesGetter` names the getter that the variant writer layers
pass down.

The footer now stores real data bytes on variant column metas instead of 0, so
the 29 checked-in golden Segment files of the 14 variant cases in
`segment_flusher_format_test` are regenerated (each grows by 2 to 4 bytes; only
those three counters of the variant metas differ). The other 59 golden cases
are byte-identical.

The footer raw_data_bytes of a variant root is also the first-batch hint of the
segment iterator's adaptive batch size predictor when a query reads the whole
variant column; it was 0 for variants. Vertical compaction's footer-based batch
size estimate still skips variant columns; its stale comment is updated.

### Release note

None

### Check List (For Author)

- Test: Unit Test (segment_flusher_format_test with the regenerated golden
  files, variant writer, compaction and segment writer tests)
- Behavior changed: Yes. Variant column metas store their data page bytes
  instead of 0.
- Does this need documentation: No

Co-Authored-By: Claude Opus 5.5 <[email protected]>
### What problem does this PR solve?

Issue Number: None

Related PR: apache#56815

Problem Summary:

Right after `write_data()` a test segment file holds only the data pages of the
column under test, so a variant writer's compressed data bytes must equal the
file's size. Check it in the shared variant segment write helpers (every
ordinary and doc mode layout they write, and the extracted subcolumn writer),
in `test_write_data_normal` (materialized subcolumns plus bucketized sparse
columns, with uncompressed and raw bytes above 0) and in
`doc_compact_writer_round_trip` (root-only writer plus doc compact writer).

### Release note

None

### Check List (For Author)

- Test: Unit Test
- Behavior changed: No
- Does this need documentation: No

Co-Authored-By: Claude Opus 5.5 <[email protected]>
### What problem does this PR solve?

Issue Number: None

Related PR: apache#56815

Problem Summary:

Compaction writes variant subcolumns, sparse columns and doc value columns as
columns of their own. Their footer metas carry data bytes but no unique id, so
`information_schema.column_data_sizes` dropped them, and with external column
meta (`storage_format = "V3"`) the sparse and doc value metas are embedded in
the root variant meta, which the scanner never looked into. After a full
compaction a variant reported only its root.

The scanner now counts a meta that has data bytes but no unique id to its
parent variant column (from its column path info), adds the metas embedded in
a variant root meta, and takes COLUMN_TYPE from the schema column, since a
subcolumn meta carries the subcolumn's type. Nothing is counted twice: the
inner metas of a variant writer carry no data bytes.

### Release note

Fix `information_schema.column_data_sizes` reporting 0 bytes for VARIANT
columns. Data written before the fix reports the new sizes once compaction
rewrites it.

### Check List (For Author)

- Test: Regression test (test_query_sys_column_data_sizes_variant, next commit)
- Behavior changed: Yes. `information_schema.column_data_sizes` counts
  compacted variant subcolumns to their variant column.
- Does this need documentation: No

Co-Authored-By: Claude Opus 5.5 <[email protected]>
…ata_sizes

### What problem does this PR solve?

Issue Number: None

Related PR: apache#56815

Problem Summary:

Cover ordinary and doc mode variants with inline (V2) and external (V3) column
meta, before and after a full compaction. The sizes of `id` and `v` must be
above 0, and the data pages of all columns must lie within the rowsets'
DATA_DISK_SIZE and cover more than half of it; they cover 91%-96%. Without
counting the metas embedded in the variant root the V3 tables drop to 35% and
11% after compaction; without resolving the parent unique id the V2 tables drop
to 3% and 2%. The table layouts are set explicitly because CI fuzzes the
variant defaults and the storage format.

### Release note

None

### Check List (For Author)

- Test: Regression test
- Behavior changed: No
- Does this need documentation: No

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@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?

@eldenmoon

Copy link
Copy Markdown
Member Author

run buildall

@hello-stephen

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

------ Round 1 ----------------------------------
============================================
q1	17661	3857	3822	3822
q2	2160	359	302	302
q3	10077	1420	796	796
q4	4679	477	351	351
q5	7536	820	559	559
q6	175	168	135	135
q7	738	780	587	587
q8	9296	1513	1584	1513
q9	5367	4153	4155	4153
q10	6811	1317	1014	1014
q11	425	270	234	234
q12	625	420	292	292
q13	18028	2613	1990	1990
q14	269	260	236	236
q15	q16	729	716	661	661
q17	1726	1099	1042	1042
q18	6458	5617	5545	5545
q19	1184	1295	1067	1067
q20	491	387	266	266
q21	5359	3001	2993	2993
q22	445	372	296	296
Total cold run time: 100239 ms
Total hot run time: 27854 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	4511	4342	4440	4342
q2	749	546	525	525
q3	4793	5349	4628	4628
q4	2184	2307	1457	1457
q5	4657	4433	4452	4433
q6	229	169	126	126
q7	1876	1708	1517	1517
q8	2345	2006	2017	2006
q9	7411	7102	6807	6807
q10	3632	3545	3102	3102
q11	521	371	353	353
q12	696	699	491	491
q13	2259	2578	1986	1986
q14	266	273	242	242
q15	q16	654	688	608	608
q17	7289	6747	6656	6656
q18	11862	11077	11710	11077
q19	1129	983	990	983
q20	2198	2182	1925	1925
q21	4909	4057	4263	4057
q22	512	439	408	408
Total cold run time: 64682 ms
Total hot run time: 57729 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-DS: Total hot run time: 152881 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 aad5a03919200dcba93a6b518784bf067dab82b6, data reload: false

query5	4327	604	456	456
query6	419	214	187	187
query7	4814	573	290	290
query8	320	178	178	178
query9	8799	4008	3975	3975
query10	450	309	257	257
query11	5976	3543	3210	3210
query12	148	91	86	86
query13	1248	575	405	405
query14	6469	4502	4229	4229
query14_1	3967	3946	4026	3946
query15	215	207	180	180
query16	986	464	424	424
query17	911	672	540	540
query18	2481	466	335	335
query19	200	182	145	145
query20	84	82	80	80
query21	222	134	114	114
query22	13008	12891	12735	12735
query23	13956	12955	12477	12477
query23_1	12690	12692	12669	12669
query24	7823	1143	657	657
query24_1	746	719	734	719
query25	591	415	347	347
query26	1298	292	165	165
query27	2668	567	339	339
query28	4552	1992	2012	1992
query29	1627	702	511	511
query30	301	219	192	192
query31	885	768	627	627
query32	138	93	96	93
query33	496	300	242	242
query34	1170	1110	637	637
query35	709	761	640	640
query36	822	773	700	700
query37	146	100	87	87
query38	1820	1742	1687	1687
query39	705	729	671	671
query39_1	629	661	657	657
query40	218	118	97	97
query41	67	61	62	61
query42	104	87	90	87
query43	334	350	298	298
query44	1351	704	722	704
query45	175	174	168	168
query46	1050	1157	711	711
query47	1482	1495	1398	1398
query48	399	399	308	308
query49	602	409	308	308
query50	933	346	294	294
query51	10383	10453	10494	10453
query52	87	87	80	80
query53	241	263	175	175
query54	266	217	196	196
query55	78	74	70	70
query56	238	213	225	213
query57	1381	1445	1393	1393
query58	283	266	242	242
query59	1984	2069	1893	1893
query60	273	232	218	218
query61	145	145	141	141
query62	391	319	276	276
query63	218	181	175	175
query64	2796	977	804	804
query65	3463	3396	3422	3396
query66	1797	408	292	292
query67	20140	19966	20006	19966
query68	3302	1472	890	890
query69	404	312	250	250
query70	904	807	833	807
query71	302	244	210	210
query72	2651	2633	2290	2290
query73	796	745	455	455
query74	4597	4506	4306	4306
query75	2286	2309	1939	1939
query76	2339	1107	752	752
query77	373	432	312	312
query78	8976	9061	8420	8420
query79	1330	1173	765	765
query80	610	498	396	396
query81	533	324	285	285
query82	666	164	126	126
query83	362	223	197	197
query84	327	148	109	109
query85	840	456	379	379
query86	331	238	232	232
query87	1978	1957	1844	1844
query88	3630	2712	2700	2700
query89	374	285	246	246
query90	1907	177	177	177
query91	173	159	126	126
query92	102	84	86	84
query93	1583	1409	883	883
query94	516	342	296	296
query95	677	386	420	386
query96	1052	816	367	367
query97	2445	2420	2306	2306
query98	159	149	143	143
query99	724	738	616	616
Total cold run time: 236553 ms
Total hot run time: 152881 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
ClickBench: Total hot run time: 23.77 s
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/clickbench-tools
ClickBench test result on commit aad5a03919200dcba93a6b518784bf067dab82b6, data reload: false

query1	0.00	0.01	0.01
query2	0.08	0.05	0.05
query3	0.26	0.14	0.13
query4	1.60	0.14	0.14
query5	0.24	0.23	0.22
query6	1.16	0.90	0.91
query7	0.04	0.00	0.00
query8	0.05	0.04	0.03
query9	0.39	0.34	0.34
query10	0.59	0.54	0.53
query11	0.20	0.14	0.15
query12	0.18	0.14	0.14
query13	0.46	0.45	0.48
query14	0.94	0.93	0.96
query15	0.60	0.58	0.57
query16	0.32	0.30	0.31
query17	1.09	1.10	1.03
query18	0.20	0.20	0.20
query19	2.02	1.93	1.92
query20	0.02	0.01	0.01
query21	15.47	0.22	0.15
query22	4.77	0.06	0.05
query23	16.14	0.30	0.11
query24	2.96	0.42	0.30
query25	0.11	0.04	0.03
query26	0.73	0.21	0.15
query27	0.04	0.04	0.04
query28	3.54	0.82	0.35
query29	12.50	4.06	3.19
query30	0.28	0.15	0.15
query31	2.77	0.56	0.31
query32	3.22	0.59	0.49
query33	3.23	3.28	3.22
query34	15.52	3.90	3.24
query35	3.22	3.20	3.24
query36	0.58	0.44	0.41
query37	0.09	0.06	0.07
query38	0.05	0.04	0.03
query39	0.04	0.03	0.03
query40	0.18	0.15	0.14
query41	0.08	0.03	0.04
query42	0.04	0.02	0.02
query43	0.04	0.04	0.03
Total cold run time: 96.04 s
Total hot run time: 23.77 s

### What problem does this PR solve?

Issue Number: None

Related PR: apache#68444

Problem Summary: A wide projected VARIANT can keep fully filtered scans on tiny batches because empty output supplies no predictor history. Add a focused reproducer checking repeated empty batches, unchanged diagnostic footer bytes, scalar footer hints, and feedback from materialized blocks. The reproducer returns 7 rows instead of the expected 4096 on the original PR head.

### Release note

None

### Check List (For Author)

- Test: ASAN BE UT: original head has 32 passing tests and the new reproducer fails; all 36 selected tests pass with the follow-up fix. UT uses GLIBC_COMPATIBILITY=OFF to avoid a host toolchain duplicate-symbol conflict. Clang-format 16, header hygiene and clang-tidy passed.
- Behavior changed: No
- Does this need documentation: No
### What problem does this PR solve?

Issue Number: None

Related PR: apache#68444

Problem Summary: Complete VARIANT raw-byte statistics shrink the initial scan batch even when a projected VARIANT is deferred and all rows are filtered by a narrow predicate. Empty output never updates the predictor, so the small batch persists until EOF. Keep the correct footer statistics and exclude VARIANT columns from the initial metadata hint, using the existing bounded probe and subsequent measured Block feedback. The focused reproducer changes from 7 to 4096 predicted rows across repeated empty batches.

### Release note

Prevent fully filtered scans with wide projected VARIANT columns from remaining on tiny adaptive batches.

### Check List (For Author)

- Test: ASAN BE UT: 36 selected tests passed, including the new red/green reproducer and VARIANT writer tests; GLIBC_COMPATIBILITY=OFF avoids a host duplicate-symbol conflict. Clang-format 16 and clang-tidy passed.
- Behavior changed: Yes, VARIANT footer statistics no longer constrain initial scan batches; measured feedback and scalar hints remain active.
- Does this need documentation: No
### What problem does this PR solve?

Issue Number: None

Related PR: apache#68444

Problem Summary: The column data size collector looks up its map twice for existing entries and repeats three counter assignments between insertion and update branches. Use try_emplace once, initialize identity fields only on insertion, and add each metadata contribution through one accumulation block. Preserve missing-field/schema checks, parent VARIANT UID attribution, and V3 child metadata traversal.

### Release note

None

### Check List (For Author)

- Test: ASAN BE UT: all 36 selected tests passed after the refactor; GLIBC_COMPATIBILITY=OFF avoids a host duplicate-symbol conflict. Clang-format 16 and clang-tidy changed-line checks passed with the existing unity-build Rowset forward declaration supplied to the analyzer.
- Behavior changed: No
- Does this need documentation: No
### What problem does this PR solve?

Problem Summary: Restore the original type-independent footer estimate for initial scan batches. Withdraw the VARIANT-specific exclusion and tests added for that policy, while retaining the column data size aggregation simplification.

### Release note

None

### Check List (For Author)

- Test: Format and header hygiene checks; restored segment iterator code matches the original PR head
- Behavior changed: Yes, remove the newly added VARIANT-specific initial batch policy
- Does this need documentation: No
### What problem does this PR solve?

Related PR: apache#68444

Problem Summary: Merge master ac92748. Regenerate the 16 conflicting segment fixtures using the merged implementation to preserve both the map_agg_v2 metadata from master and the VARIANT data size metadata from this PR. All 132 other generated fixtures match the existing merged tree.

### Release note

None

### Check List (For Author)

- Test: ASAN BE unit tests 44/44 pass both when generating fixtures and when verifying the checked-in fixtures; clang-format 16 and header hygiene pass
- Behavior changed: No, resolve test fixture conflicts while retaining both branches' changes
- Does this need documentation: No
@eldenmoon

Copy link
Copy Markdown
Member Author

run buildall

@hello-stephen

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

------ Round 1 ----------------------------------
============================================
q1	17613	5667	5636	5636
q2	2145	328	255	255
q3	10164	1450	855	855
q4	4680	480	349	349
q5	7444	808	533	533
q6	195	187	151	151
q7	807	812	598	598
q8	9234	1493	1253	1253
q9	5836	4628	4624	4624
q10	6848	1302	1030	1030
q11	469	254	233	233
q12	629	408	279	279
q13	18081	3130	2405	2405
q14	278	275	249	249
q15	q16	730	726	655	655
q17	1349	749	570	570
q18	7226	6282	6201	6201
q19	1124	1098	621	621
q20	386	343	231	231
q21	5028	2239	2358	2239
q22	363	313	270	270
Total cold run time: 100629 ms
Total hot run time: 29237 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	6328	6267	6261	6261
q2	699	574	526	526
q3	5260	5417	4939	4939
q4	2035	2138	1548	1548
q5	5310	5682	5896	5682
q6	284	200	146	146
q7	2436	2122	1912	1912
q8	3357	3065	2889	2889
q9	8407	8367	8318	8318
q10	3783	3694	3313	3313
q11	641	449	407	407
q12	697	720	514	514
q13	2959	3221	2447	2447
q14	325	314	314	314
q15	q16	701	755	754	754
q17	8439	7575	7385	7385
q18	13235	12345	13204	12345
q19	1072	906	905	905
q20	2234	2220	1991	1991
q21	5956	4731	4796	4731
q22	498	438	411	411
Total cold run time: 74656 ms
Total hot run time: 67738 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-DS: Total hot run time: 151644 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 07d1a5c83382cd41c9e9650fdbd4a1c1479ccfc0, data reload: false

query5	4319	588	449	449
query6	421	211	195	195
query7	4815	449	222	222
query8	313	186	164	164
query9	8766	3916	3911	3911
query10	468	350	265	265
query11	5939	3449	3168	3168
query12	146	90	85	85
query13	1246	444	318	318
query14	6557	4984	4454	4454
query14_1	4229	4232	4221	4221
query15	205	200	200	200
query16	957	442	431	431
query17	881	658	544	544
query18	2426	430	310	310
query19	202	161	140	140
query20	82	79	79	79
query21	214	138	112	112
query22	12959	13053	12776	12776
query23	13193	12547	12303	12303
query23_1	12306	12178	12314	12178
query24	7113	829	456	456
query24_1	466	465	474	465
query25	540	417	370	370
query26	1294	258	136	136
query27	2756	439	270	270
query28	4622	1914	1895	1895
query29	1574	603	471	471
query30	321	255	182	182
query31	891	760	647	647
query32	134	83	91	83
query33	490	278	232	232
query34	928	847	504	504
query35	744	748	653	653
query36	844	834	723	723
query37	120	99	87	87
query38	1793	1779	1702	1702
query39	707	716	673	673
query39_1	635	640	659	640
query40	215	112	97	97
query41	67	62	65	62
query42	87	88	79	79
query43	365	377	323	323
query44	1283	676	685	676
query45	178	178	165	165
query46	844	959	548	548
query47	3026	2918	2924	2918
query48	292	300	210	210
query49	568	385	294	294
query50	676	284	213	213
query51	10399	10432	10696	10432
query52	83	79	68	68
query53	183	205	149	149
query54	237	187	172	172
query55	74	66	69	66
query56	223	221	207	207
query57	1621	1594	1553	1553
query58	274	252	248	248
query59	2349	2391	2134	2134
query60	259	237	223	223
query61	150	147	144	144
query62	397	344	286	286
query63	197	163	166	163
query64	2721	892	761	761
query65	3445	3379	3370	3370
query66	1834	406	303	303
query67	20562	20137	20043	20043
query68	3102	997	611	611
query69	384	295	247	247
query70	906	855	834	834
query71	312	230	205	205
query72	2752	2603	2283	2283
query73	506	521	295	295
query74	4563	4467	4288	4288
query75	2348	2281	1934	1934
query76	2301	1013	610	610
query77	353	389	294	294
query78	8991	8950	8468	8468
query79	953	841	512	512
query80	1024	424	347	347
query81	568	323	272	272
query82	581	136	105	105
query83	306	191	174	174
query84	315	126	103	103
query85	855	428	363	363
query86	430	233	235	233
query87	2020	1938	1830	1830
query88	3565	2679	2631	2631
query89	344	295	253	253
query90	1835	181	171	171
query91	165	154	125	125
query92	101	86	88	86
query93	981	971	565	565
query94	578	312	252	252
query95	582	402	330	330
query96	667	507	231	231
query97	2473	2433	2333	2333
query98	158	154	141	141
query99	781	775	631	631
Total cold run time: 234667 ms
Total hot run time: 151644 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
ClickBench: Total hot run time: 24.54 s
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/clickbench-tools
ClickBench test result on commit 07d1a5c83382cd41c9e9650fdbd4a1c1479ccfc0, data reload: false

query1	0.01	0.01	0.00
query2	0.11	0.06	0.05
query3	0.27	0.12	0.11
query4	1.61	0.12	0.12
query5	0.27	0.24	0.25
query6	1.18	0.69	0.67
query7	0.04	0.01	0.01
query8	0.06	0.04	0.04
query9	0.45	0.36	0.35
query10	0.58	0.55	0.58
query11	0.21	0.15	0.14
query12	0.19	0.15	0.14
query13	0.51	0.51	0.50
query14	0.98	0.97	0.97
query15	0.63	0.62	0.61
query16	0.31	0.36	0.35
query17	1.14	1.16	1.15
query18	0.22	0.21	0.21
query19	2.14	1.98	1.96
query20	0.02	0.01	0.02
query21	15.51	0.28	0.15
query22	4.48	0.06	0.05
query23	16.25	0.33	0.12
query24	3.23	0.68	0.42
query25	0.13	0.08	0.04
query26	1.13	0.25	0.16
query27	0.04	0.03	0.04
query28	1.84	0.57	0.42
query29	12.53	4.21	3.31
query30	0.29	0.15	0.13
query31	2.77	0.58	0.33
query32	3.23	0.62	0.52
query33	3.28	3.18	3.18
query34	15.59	4.04	3.37
query35	3.35	3.34	3.33
query36	0.55	0.44	0.47
query37	0.10	0.06	0.07
query38	0.05	0.04	0.04
query39	0.04	0.04	0.03
query40	0.17	0.15	0.14
query41	0.10	0.03	0.03
query42	0.04	0.03	0.03
query43	0.04	0.04	0.03
Total cold run time: 95.67 s
Total hot run time: 24.54 s

@hello-stephen

Copy link
Copy Markdown
Contributor

BE Regression && UT Coverage Report

Increment line coverage 100.00% (13/13) 🎉

Increment coverage report
Complete coverage report

Category Coverage
Function Coverage 76.74% (35220/45896)
Line Coverage 61.92% (397919/642627)
Region Coverage 58.32% (335620/575490)
Branch Coverage 59.24% (154467/260769)

@eldenmoon

Copy link
Copy Markdown
Member Author

/review

@airborne12 airborne12 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No actionable findings at head 07d1a5c83382cd41c9e9650fdbd4a1c1479ccfc0. Reviewed all 40 changed paths, including 29 binary fixtures, with two complete-scope reviewers and one independent risk reviewer. All returned NO_NEW_VALUABLE_FINDINGS; the review converged in 1 round. There were no existing inline threads or confirmed existing blockers.

Critical checkpoint conclusions:

  • Goal and evidence: Writer totals and scanner parent attribution cover VARIANT sizes through load and compaction. UT assertions compare compressed counters with actual appended bytes; regression covers ordinary/doc mode, V2/V3 metadata, and before/after compaction.
  • Scope and reuse: The change stays focused on accounting and reuses existing scalar/complex getters through DataBytesGetter.
  • Concurrency and locks: No new threads, locks or lock ordering. Scanner aggregation is local to existing rowset snapshots; segment I/O remains outside tablet snapshot locks.
  • Lifecycle and initialization: Both production counter-read sites follow successful finalization and data writes. Empty, all-null, root-only, extracted and doc-compaction paths create their inner owners before reads. No new global initialization or ownership cycle.
  • Configuration: No production configuration added or changed; tests select existing modes.
  • Compatibility: Existing optional footer fields receive real counters; no wire fields, encoding or protocol changes. Historical zero/missing writer counters cannot be reconstructed until segments are rewritten. No new libc/API dependency identified in the source changes.
  • Parallel paths: Traced ordinary/doc, sparse single/bucket, root-only/extracted/doc compaction, complex inner writers, V2/V3 metadata, and the common local/cloud scanner path.
  • Conditions and errors: Counter-bearing extracted metas carry parent/path information. Inner metas have no separate counters, while V3 embeds separately counted sparse/doc metas once, so the new traversal does not duplicate their aggregates. Existing Status propagation remains intact.
  • Test coverage: The exact-byte writer assertions and end-to-end matrix target the accounting boundaries. Empty/all-null ownership and supported typed/complex paths were also checked statically; no new negative-result behavior was introduced.
  • Test results and fixtures: All eight ordered two-column regression output groups match the four pre/post-compaction checks. Static wire inspection of all 29 changed fixtures verified both old/new footer CRC32C values, unchanged data/index payloads and other metadata, and only 93 existing VARIANT byte-counter fields changing from zero to positive; files grow by 2 or 4 bytes.
  • Observability: This repairs the existing column-size observability surface; no new execution stage requires extra logs or metrics.
  • Transactions and persistence: Only existing segment statistics values change. No FE EditLog, master failover, transaction visibility, version or delete-bitmap logic changes.
  • Writes and atomicity: Existing segment write/finalize/publication and failure propagation remain intact; statistics are read after successful writes.
  • FE/BE variables: None introduced; no additional propagation paths apply.
  • Performance and memory: Three linear passes over existing inner writers at finalization add no buffers or retained allocations. Scanner aggregation uses one map insertion/lookup. Query raw-byte hints remain bounded by the initial probe and original row maximum, then measured block sizes replace them; variant compaction retains its fallback.
  • Other BE checkpoints: No new includes, hub dependency edges, PCH/gate changes, explicit template instantiations, header renames, or source-cpp test inclusions. No additional substantiated issue found after the final sweep.

User focus: No additional focus was supplied.

Limits: Static review only, as required. No builds, tests, ASAN, performance measurements, compiled ELF audit or live mixed-version execution were performed. Inspected output contents and fixture bytes do not establish their generation provenance. No unresolved correctness candidates or uncovered changed paths remain within this review scope.

Review converged after 1 round(s).

@eldenmoon
eldenmoon merged commit 211a79a into apache:master Oct 19, 2026
38 checks passed
@github-actions

Copy link
Copy Markdown
Contributor

PR approved by anyone and no changes requested.

@github-actions github-actions Bot added the approved Indicates a PR has been approved by one committer. label Oct 19, 2026
@github-actions

Copy link
Copy Markdown
Contributor

PR approved by at least one committer and no changes requested.

eldenmoon added a commit that referenced this pull request Oct 19, 2026
eldenmoon added a commit that referenced this pull request Oct 19, 2026
@eldenmoon
eldenmoon deleted the fix-variant-column-data-sizes branch October 19, 2026 09:27
yiguolei pushed a commit that referenced this pull request Oct 20, 2026
…_data_sizes (#69259)

cherry-pick #68444

Adapted to branch-4.2:

- `be/test/storage/test_data/segment_flusher_format/*`: the fixtures the
original commit
updates do not exist on branch-4.2 (that test was never backported), so
they stay deleted.
- branch-4.2 still has the V1 variant writer. `VariantColumnWriterImpl`
may own only a V1
writer, so `get_total_data_pages_bytes` dispatches to
`VariantV1ColumnWriter`, which sums
its root, subcolumn and binary writers, instead of dereferencing a null
V2 writer.
  `VariantSubcolumnWriter` reports 0 before its writer exists.

Tested locally with
`./run-be-ut.sh --run
--filter='VariantColumnWriterReaderTest.*:VariantUtilTest.*'`
(branch-4.2 code + this pick, RELEASE build):

- 77 tests passed, including
`VariantColumnWriterReaderTest.test_write_data_normal`,
`doc_compact_writer_round_trip` and the two writer helpers that now
assert the variant
  data page bytes, plus all 21 `VariantUtilTest` tests.
- `VariantColumnWriterReaderTest.test_nested_iter` fails, but it fails
on branch-4.2 without
this change as well (`_process_nested_columns` no longer returns an
error for a different
  array offset), so it is not caused by this pick.

The new regression suite
`query_p0/system/test_query_sys_column_data_sizes_variant` was not
run locally (needs a cluster).
sdk2 pushed a commit to sdk2/doris that referenced this pull request Oct 21, 2026
…ring writers (apache#69221)

### What problem does this PR solve?

Issue Number: CIR-22037 (related: apache#66298)

VARIANT compaction can fail forever with `E-3113 string column length is
too large`.
`ColumnStr<uint32_t>` rejects more han 4 GiB of uncompressed chars,
while vertical compaction
plans output segments from **compressed** bytes. High-compression-ratio
VARIANT data reaches the
uint32 offset limit long before the planned segment reaches
`vertical_compaction_max_segment_size`.

The writer side made this deterministic: the VARIANT V2 writer buffered
a whole output segment in
memory before flushing it.

Reproduced on master with 1.2M rows x 4 KiB of VARIANT payload (4.9 GiB
uncompressed, ~8 MiB on
disk) and `vertical_compaction_max_segment_size=256MiB`:

```
[E-3113] string column length is too large: total_length=4295296512,
limit=4294967295, element_number=1044576, rows=1043584
  VariantV2ColumnWriter::append -> ColumnStr<unsigned int>::insert_range_from
```

### What changed?

1. **Stream the root-only VARIANT writer**
(`variant/v2/variant_column_writer.*`).
The root column writer is created at `init()` and every input batch is
appended to it, so the
writer never retains a segment-sized `ColumnString` (`_root_jsonb` is
gone). `finalize()` only
records the row count; `estimate_buffer_size()` reports the current page
instead of the whole
   segment.

2. **Bound the writers that still buffer** (`compaction/compaction.*`,
`common/config.*`).
When the compaction schema still selects a segment-buffering writer -
the shredder (no
extracted subcolumns, e.g.
`enable_vertical_compact_variant_subcolumns=false`) or
`VariantSubcolumnWriter` (extracted VARIANT subcolumns) - clamp the
per-segment row budget
   using the input segments' VARIANT `raw_data_bytes` and
`variant_compaction_max_segment_uncompressed_bytes` (2 GiB default, 0
disables).
`raw_data_bytes` is the pre-encoding size the writer buffers;
`uncompressed_data_bytes` is the
encoded page size and can be orders of magnitude smaller for
dictionary-encoded strings
(measured 142,560 vs 4,944,000,000 for the same segment). The streaming
path is not clamped, so
   its segment layout does not change.

Depends on apache#68444, which makes variant writers report
`raw/compressed/uncompressed` data page
bytes in the segment footer (first commit is that change, kept here so
the branch is testable).

### Tests

-
`VariantColumnWriterReaderTest.test_variant_root_writer_streams_per_batch`
(new):
writes 4,000 x 4 KiB root scalars in 1,000-row batches and asserts the
buffered bytes stay below
  two batches. Red/green verified locally with `doris_be_test`:
  - red (buffering writer): `actual: 16428000 vs 8192000` -> FAILED
  - green (streamed writer): `[ OK ] ... (156 ms)` -> PASSED
- Variant writer data page byte counters equal the bytes appended to the
file right after
  `write_data()` (ordinary, extracted subcolumn, doc compact writer).
- `information_schema.column_data_sizes` reports VARIANT
compressed/uncompressed/raw bytes
  (regression suite `test_query_sys_column_data_sizes_variant`).
- Manual end-to-end on a single-BE cluster (1.2M x 4 KiB):
- default path: **1 segment, no E-3113**, checksum unchanged
(count=1200000,
sum(len)=4927200000, sum(crc32)=2041942614000000), BE RSS peak +114 MiB
(was +5 GiB).
- `enable_vertical_compact_variant_subcolumns=false` (shredder): clamp
1,200,001 -> 521,233
    rows per segment, **3 segments, no E-3113**, same checksum.
- **Sparse columns**: `variant_max_subcolumns_count=1` with a 4 KiB
`z_big` path that is not
materialized (sparse), extract off. Without the budget: E-3113 at
4,294,970,386 bytes
(`serialize_column_to_jsonb_vector`). With the budget: clamp 1,200,001
-> 517,465 rows per
    segment, 3 segments, no E-3113, checksum identical to a fresh load
    (count=1200000, sum(len)=4981200000, sum(crc32)=252636363600000).

### Remaining

- Non-vertical compaction does not use the segment row budget.
- Segments written before the footer raw-byte metadata existed (raw = 0)
cannot be estimated; the
  streamed root path still covers them, the shredder path does not.
- Doc mode relies on the raw-byte budget.

### Release note

VARIANT compaction no longer buffers a whole output segment in one
`ColumnString`.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved Indicates a PR has been approved by one committer. dev/4.2.0-merged reviewed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants