Skip to content

[improvement](be) Write Variant V2 directly to Parquet Variant - #67424

Draft
eldenmoon wants to merge 1 commit into
apache:masterfrom
eldenmoon:branch-variant-v2-direct-parquet
Draft

[improvement](be) Write Variant V2 directly to Parquet Variant#67424
eldenmoon wants to merge 1 commit into
apache:masterfrom
eldenmoon:branch-variant-v2-direct-parquet

Conversation

@eldenmoon

@eldenmoon eldenmoon commented Sep 2, 2026

Copy link
Copy Markdown
Member

What problem does this PR solve?

Issue Number: None

Related PR: None

Problem Summary: Variant V2 Parquet export renders the existing metadata/value encoding through JSON and UTF-8 before writing Parquet. When return_object_data_as_binary is enabled, this change selects Arrow's Parquet Variant extension in VParquetTransformer and lets DataTypeVariantV2SerDe append the existing metadata/value bytes with exact buffer reservation. The shared Arrow converter handles extension arrays through the standard ExtensionType storage contract without Parquet-specific type-name knowledge. The default remains the legacy UTF-8 representation, preserving current Doris export-to-Stream-Load behavior. On the fixed 10 GB workload, the enabled direct path decreases wall median from 77.7376 to 53.0676 seconds and BE CPU from 245.04 to 213.88 core-seconds, improvements of 31.73% and 12.72% respectively.

DuckDB 1.5.2 recognizes and decodes the direct output as VARIANT. Doris legacy Parquet schema inference and Stream Load do not yet consume the Parquet VARIANT logical type end to end, so direct encoding is explicitly opt-in in this PR.

Release note

When return_object_data_as_binary is enabled, Variant V2 Parquet export writes the Parquet Variant logical type directly. The default remains the legacy UTF-8 representation.

Check List (For Author)

  • Test

    • Regression test
    • Unit Test
      • ASAN BE UT before the final generic ExtensionType cleanup: DataTypeSerDeArrowTest.* and VParquetTransformerTest.*, 15/15 passed.
      • Final cleanup validation: clang-format and check-format passed, and the modified source compiled in the ASAN UT build. The focused UT rerun did not reach test execution because the ldb toolchain compatibility library duplicated getrandom; the GLIBC_COMPATIBILITY=OFF retry was blocked by isolated-worktree submodule metadata permissions.
      • File-level tests use the actual VParquetTransformer, inspect the Parquet footer, read the file through Arrow Parquet, and compare every non-SQL-null row with the source Variant canonical value.
      • Coverage includes object, array, string, positive and negative integers, floating point, booleans, Variant null, SQL null, direct opt-in, and default UTF-8 compatibility.
    • Manual test
      • Release build before the final generic ExtensionType cleanup: env BUILD_TYPE=RELEASE GLIBC_COMPATIBILITY=OFF ./build.sh --be --hive-udf passed.
      • DuckDB 1.5.2 recognized all 2,906,455 exported rows as VARIANT, reported no null values, and decoded sampled objects.
      • One warmup and three measured trials on the fixed 10 GB workload.
    • No need to test or manual test. Explain why:
  • Behavior changed:

    • No.
    • Yes. Opt-in Variant V2 Parquet export uses the Parquet Variant logical type; default output is unchanged.
  • Does this need documentation?

    • No. This remains experimental pending Doris reader/load integration.
    • Yes.

Check List (For Reviewer who merge this PR)

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

@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

@eldenmoon
eldenmoon force-pushed the branch-variant-v2-direct-parquet branch from 92ee243 to df621fe Compare September 2, 2026 04:28
@eldenmoon

Copy link
Copy Markdown
Member Author

run buildall

@hello-stephen

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

------ Round 1 ----------------------------------
============================================
q1	17568	3057	3086	3057
q2	2119	245	220	220
q3	10235	867	533	533
q4	4674	252	208	208
q5	7667	588	377	377
q6	136	119	94	94
q7	528	504	393	393
q8	9251	858	844	844
q9	3435	2396	2387	2387
q10	6518	850	705	705
q11	385	201	181	181
q12	616	267	200	200
q13	18129	1523	1163	1163
q14	164	151	141	141
q15	q16	443	397	364	364
q17	1339	930	840	840
q18	3108	2251	2258	2251
q19	1261	895	732	732
q20	381	295	204	204
q21	5638	1822	1826	1822
q22	325	274	232	232
Total cold run time: 93920 ms
Total hot run time: 16948 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	3418	3316	3301	3301
q2	506	398	366	366
q3	2218	2316	2128	2128
q4	1203	1195	900	900
q5	2187	2127	2139	2127
q6	166	122	90	90
q7	1132	953	878	878
q8	1595	1408	1412	1408
q9	3121	3093	3083	3083
q10	1872	1789	1644	1644
q11	357	271	250	250
q12	446	427	350	350
q13	1492	1531	1173	1173
q14	175	164	158	158
q15	q16	388	400	351	351
q17	3552	3242	3216	3216
q18	4795	4401	4729	4401
q19	840	897	870	870
q20	1024	972	836	836
q21	3830	3159	3330	3159
q22	406	350	332	332
Total cold run time: 34723 ms
Total hot run time: 31021 ms

@hello-stephen

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

query5	4263	424	340	340
query6	390	138	129	129
query7	4932	437	236	236
query8	295	127	120	120
query9	8694	2887	2882	2882
query10	401	228	192	192
query11	5382	1028	917	917
query12	129	71	70	70
query13	1194	445	303	303
query14	6079	2229	2075	2075
query14_1	1976	1962	1993	1962
query15	173	129	117	117
query16	919	388	342	342
query17	784	439	349	349
query18	2340	339	229	229
query19	165	137	104	104
query20	73	70	69	69
query21	199	98	84	84
query22	5450	5330	5354	5330
query23	6686	6327	6010	6010
query23_1	5942	6026	6051	6026
query24	7254	1087	764	764
query24_1	774	781	784	781
query25	404	302	236	236
query26	1226	240	126	126
query27	2792	417	246	246
query28	4697	1525	1486	1486
query29	919	442	340	340
query30	254	159	128	128
query31	809	400	353	353
query32	120	83	72	72
query33	447	219	186	186
query34	987	853	486	486
query35	395	404	343	343
query36	580	600	538	538
query37	117	79	68	68
query38	999	847	842	842
query39	490	504	501	501
query39_1	447	454	483	454
query40	198	88	79	79
query41	56	52	51	51
query42	75	71	72	71
query43	241	241	207	207
query44	1004	539	550	539
query45	109	105	97	97
query46	762	882	525	525
query47	782	776	721	721
query48	316	312	235	235
query49	544	241	190	190
query50	798	271	198	198
query51	8498	8143	8179	8143
query52	71	70	61	61
query53	197	209	152	152
query54	238	178	173	173
query55	82	63	57	57
query56	202	282	167	167
query57	685	692	670	670
query58	222	182	166	166
query59	1216	1250	1104	1104
query60	241	200	174	174
query61	137	138	128	128
query62	362	218	174	174
query63	172	140	146	140
query64	2897	795	570	570
query65	1605	1603	1636	1603
query66	1785	274	209	209
query67	10182	9718	9528	9528
query68	3003	1171	756	756
query69	334	230	209	209
query70	687	636	612	612
query71	259	183	164	164
query72	2301	1790	1541	1541
query73	675	584	339	339
query74	1993	1234	1128	1128
query75	1189	1108	974	974
query76	2374	744	562	562
query77	258	267	225	225
query78	3932	3786	3315	3315
query79	2766	793	613	613
query80	1620	324	286	286
query81	512	159	131	131
query82	626	120	100	100
query83	282	219	196	196
query84	295	111	89	89
query85	807	361	300	300
query86	445	183	172	172
query87	1009	962	897	897
query88	2872	2099	2100	2099
query89	284	195	173	173
query90	1969	134	125	125
query91	136	124	99	99
query92	87	74	66	66
query93	1905	1085	700	700
query94	630	257	227	227
query95	505	319	230	230
query96	859	594	280	280
query97	1041	1029	1000	1000
query98	163	137	129	129
query99	438	343	321	321
Total cold run time: 179559 ms
Total hot run time: 82200 ms

@hello-stephen

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

query1	0.00	0.01	0.00
query2	0.07	0.04	0.03
query3	0.25	0.11	0.11
query4	1.61	0.10	0.09
query5	0.17	0.16	0.16
query6	1.24	0.67	0.68
query7	0.04	0.01	0.00
query8	0.05	0.03	0.03
query9	0.28	0.21	0.22
query10	0.34	0.35	0.34
query11	0.17	0.11	0.11
query12	0.15	0.12	0.12
query13	0.32	0.31	0.31
query14	0.45	0.45	0.45
query15	0.35	0.36	0.36
query16	0.23	0.24	0.23
query17	0.63	0.70	0.64
query18	0.18	0.17	0.16
query19	1.18	1.20	1.15
query20	0.01	0.00	0.01
query21	15.45	0.15	0.15
query22	5.03	0.04	0.04
query23	16.15	0.25	0.10
query24	3.00	0.29	0.25
query25	0.10	0.04	0.02
query26	0.76	0.17	0.13
query27	0.04	0.04	0.02
query28	3.58	0.59	0.28
query29	12.42	3.16	2.59
query30	0.24	0.12	0.12
query31	2.76	0.36	0.17
query32	3.52	0.32	0.24
query33	1.36	1.46	1.39
query34	15.37	2.18	1.79
query35	1.75	1.76	1.72
query36	0.47	0.28	0.29
query37	0.06	0.04	0.04
query38	0.04	0.03	0.03
query39	0.03	0.02	0.03
query40	0.12	0.08	0.08
query41	0.08	0.03	0.03
query42	0.04	0.02	0.03
query43	0.03	0.03	0.02
Total cold run time: 90.12 s
Total hot run time: 14.7 s

### What problem does this PR solve?

Issue Number: None

Related PR: None

Problem Summary: Variant V2 Parquet export renders existing metadata/value encoding through JSON and UTF-8 before writing Parquet. When return_object_data_as_binary is enabled, select Arrow's Parquet Variant extension in the Parquet transformer and let DataTypeVariantV2SerDe append the existing metadata/value bytes with exact buffer reservation. Keep the default UTF-8 export for compatibility. The common Arrow converter handles extension arrays through the standard ExtensionType storage contract without Parquet-specific type-name knowledge. On the fixed 10 GB workload, the enabled direct path decreases wall median from 77.7376 to 53.0676 seconds and BE CPU from 245.04 to 213.88 core-seconds, improvements of 31.73% and 12.72% respectively. DuckDB recognizes and decodes the output as VARIANT; Doris legacy Parquet schema inference and Stream Load do not yet consume this logical type end to end.

### Release note

When return_object_data_as_binary is enabled, Variant V2 Parquet export writes the Parquet Variant logical type directly. The default remains the legacy UTF-8 representation.

### Check List (For Author)

- Test: Unit Test, Release build, and manual performance/format validation
    - ASAN BE UT before the final generic ExtensionType cleanup: DataTypeSerDeArrowTest.* and VParquetTransformerTest.*, 15/15 passed
    - Final cleanup validation: clang-format and check-format passed; the modified source compiled in the ASAN UT build. The focused UT rerun did not reach test execution because the ldb toolchain compatibility library duplicated getrandom; the GLIBC_COMPATIBILITY=OFF retry was blocked by isolated-worktree submodule metadata permissions
    - Unit coverage: actual Parquet write, footer inspection, Arrow readback, object, array, string, integers, floating point, booleans, Variant null, and SQL null canonical equality
    - Release build before the final generic ExtensionType cleanup: env BUILD_TYPE=RELEASE GLIBC_COMPATIBILITY=OFF ./build.sh --be --hive-udf passed
    - Manual test: DuckDB 1.5.2 recognized the full 2,906,455-row export as VARIANT, reported no null values, and decoded sampled objects
    - Performance benchmark: one warmup and three trials on the fixed 10 GB workload
- Behavior changed: Yes, opt-in Variant V2 Parquet export uses the Parquet Variant logical type
- Does this need documentation: No, this remains experimental pending Doris reader/load integration
@eldenmoon
eldenmoon force-pushed the branch-variant-v2-direct-parquet branch from df621fe to 225cff7 Compare September 2, 2026 08:22
@eldenmoon

Copy link
Copy Markdown
Member Author

run buildall

@hello-stephen

Copy link
Copy Markdown
Contributor

BE UT Coverage Report

Increment line coverage 100.00% (25/25) 🎉

Increment coverage report
Complete coverage report

Category Coverage
Function Coverage 62.99% (29596/46987)
Line Coverage 48.01% (310307/646281)
Region Coverage 43.60% (250612/574783)
Branch Coverage 45.12% (116603/258425)

@hello-stephen

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

------ Round 1 ----------------------------------
============================================
q1	17569	3007	3024	3007
q2	2169	261	234	234
q3	10191	957	529	529
q4	4681	246	205	205
q5	7685	581	380	380
q6	138	115	95	95
q7	520	483	390	390
q8	9236	872	943	872
q9	3534	2389	2385	2385
q10	6492	865	717	717
q11	390	194	180	180
q12	608	257	199	199
q13	18131	1564	1159	1159
q14	163	149	148	148
q15	q16	438	394	360	360
q17	1281	876	793	793
q18	3120	2238	2249	2238
q19	1267	889	775	775
q20	378	278	204	204
q21	5569	1761	1861	1761
q22	332	276	237	237
Total cold run time: 93892 ms
Total hot run time: 16868 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	3410	3343	3319	3319
q2	510	386	374	374
q3	2207	2293	2141	2141
q4	1187	1169	897	897
q5	2177	2125	2092	2092
q6	169	115	88	88
q7	1008	921	866	866
q8	1608	1413	1414	1413
q9	3128	3118	3092	3092
q10	1853	1813	1647	1647
q11	355	273	249	249
q12	455	426	345	345
q13	1472	1566	1148	1148
q14	185	172	162	162
q15	q16	394	400	359	359
q17	3609	3302	3190	3190
q18	4793	4392	4723	4392
q19	861	917	887	887
q20	1010	974	827	827
q21	3812	3090	3319	3090
q22	388	354	333	333
Total cold run time: 34591 ms
Total hot run time: 30911 ms

@hello-stephen

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

query5	4283	418	341	341
query6	387	134	120	120
query7	4954	427	232	232
query8	308	127	123	123
query9	8717	2924	2906	2906
query10	404	226	189	189
query11	5382	1051	919	919
query12	135	71	71	71
query13	1205	475	325	325
query14	6038	2247	2134	2134
query14_1	2005	1995	1983	1983
query15	170	121	115	115
query16	934	397	367	367
query17	819	477	377	377
query18	2347	340	247	247
query19	167	145	116	116
query20	86	70	73	70
query21	210	103	85	85
query22	5474	5406	5387	5387
query23	6932	6291	5984	5984
query23_1	6216	5909	6040	5909
query24	7296	1112	771	771
query24_1	781	829	793	793
query25	443	310	273	273
query26	1224	224	133	133
query27	2805	427	262	262
query28	4671	1515	1523	1515
query29	953	460	364	364
query30	250	158	136	136
query31	829	402	330	330
query32	135	79	76	76
query33	466	221	186	186
query34	1003	850	483	483
query35	409	400	337	337
query36	570	591	518	518
query37	122	86	72	72
query38	1015	864	824	824
query39	493	495	465	465
query39_1	460	453	463	453
query40	208	94	81	81
query41	61	58	56	56
query42	113	74	70	70
query43	239	242	205	205
query44	1029	549	551	549
query45	115	108	101	101
query46	763	849	533	533
query47	762	757	698	698
query48	311	314	240	240
query49	547	237	193	193
query50	716	254	205	205
query51	8107	8102	8235	8102
query52	66	72	59	59
query53	200	224	221	221
query54	250	166	169	166
query55	72	59	58	58
query56	206	156	156	156
query57	661	663	662	662
query58	198	163	177	163
query59	1214	1214	1098	1098
query60	236	181	173	173
query61	121	118	119	118
query62	382	210	181	181
query63	174	139	148	139
query64	2802	781	590	590
query65	1624	1634	1614	1614
query66	1791	251	205	205
query67	10048	9954	9562	9562
query68	3023	1169	763	763
query69	350	224	203	203
query70	648	632	615	615
query71	253	180	166	166
query72	2324	1712	1577	1577
query73	668	591	319	319
query74	1976	1245	1149	1149
query75	1185	1106	964	964
query76	2353	775	554	554
query77	248	253	222	222
query78	3960	3598	3231	3231
query79	2836	881	599	599
query80	1613	330	283	283
query81	516	157	136	136
query82	631	124	101	101
query83	282	219	199	199
query84	301	110	89	89
query85	823	359	291	291
query86	478	182	170	170
query87	1010	965	888	888
query88	3208	2107	2087	2087
query89	285	203	179	179
query90	2205	130	127	127
query91	134	119	101	101
query92	94	69	72	69
query93	2866	1084	736	736
query94	643	251	224	224
query95	537	331	221	221
query96	832	552	268	268
query97	1122	1053	1019	1019
query98	175	131	128	128
query99	420	355	314	314
Total cold run time: 181554 ms
Total hot run time: 82340 ms

@hello-stephen

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

query1	0.01	0.00	0.00
query2	0.08	0.03	0.04
query3	0.25	0.12	0.10
query4	1.60	0.10	0.11
query5	0.17	0.17	0.15
query6	1.25	0.71	0.69
query7	0.03	0.01	0.00
query8	0.05	0.03	0.03
query9	0.29	0.21	0.22
query10	0.36	0.35	0.35
query11	0.16	0.12	0.12
query12	0.15	0.12	0.12
query13	0.31	0.30	0.30
query14	0.44	0.45	0.44
query15	0.35	0.35	0.34
query16	0.23	0.23	0.21
query17	0.74	0.69	0.67
query18	0.17	0.17	0.16
query19	1.22	1.09	1.16
query20	0.02	0.01	0.01
query21	15.47	0.16	0.13
query22	5.10	0.05	0.04
query23	16.15	0.25	0.10
query24	3.00	0.31	0.25
query25	0.10	0.05	0.03
query26	0.75	0.16	0.12
query27	0.04	0.04	0.03
query28	3.63	0.53	0.27
query29	12.47	3.16	2.56
query30	0.26	0.11	0.12
query31	2.76	0.37	0.17
query32	3.51	0.31	0.24
query33	1.35	1.37	1.36
query34	15.33	2.19	1.74
query35	1.77	1.76	1.74
query36	0.46	0.28	0.28
query37	0.08	0.04	0.04
query38	0.05	0.02	0.02
query39	0.04	0.03	0.02
query40	0.11	0.07	0.07
query41	0.07	0.03	0.02
query42	0.03	0.02	0.02
query43	0.04	0.03	0.03
Total cold run time: 90.45 s
Total hot run time: 14.51 s

@hello-stephen

Copy link
Copy Markdown
Contributor

BE Regression && UT Coverage Report

Increment line coverage 100.00% (25/25) 🎉

Increment coverage report
Complete coverage report

Category Coverage
Function Coverage 76.07% (34621/45510)
Line Coverage 61.13% (390579/638910)
Region Coverage 57.25% (327800/572592)
Branch Coverage 58.05% (149598/257686)

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.

2 participants