Hi, all. I conducted a comparative test between Cl...
# questions-and-troubleshooting
g
Hi, all. I conducted a comparative test between ClickHouse and StarRocks. Both were deployed as single-node versions on a server with 96 CPU cores, 320GB of RAM, and 4.5TB of disk storage. ClickHouse version: v25.9.3.1 StarRocks version: StarRocks-4.0.1-ubuntu-amd64 The test used an actual SQL query from a production environment for aggregation: joining one table with 16.22 million records to another with 288 records, and left joining a third table with 14 records. 1、StarRocks took 12.5 seconds. (Measurement method: I enter the Queries page and view the Finished Queries, which takes 12.5 seconds in total from the web page (port 8030)) The following parameters were adjusted for StarRocks: SET is_report_success = true; SET parallel_fragment_exec_instance_num = 64; SET global_dict_optimize_enabled = true; SET enable_vectorized_engine = true; SET exec_mem_limit = 107374182400 * 2; SET runtime_filter_mode = "GLOBAL"; SET broadcast_row_limit = 1000000; SET pipeline_dop = 64; 2、ClickHouse took only 2 seconds. (Measurement method: Executed via
clickhouse-client
, which directly displays query execution time.) Why did StarRocks take longer in this test? Are there potential issues with the testing approach? Do you have any suggestions for improvement? Looking forward to your suggestions. Thanks a lot.
е
g
Hi, @Евгений Шишкин See the attachment for profile file
е
seems like LOCAL_MERGE_SOURCE problem try setting parallel_fragment_exec_instance_num and pipeline_dop to default values, i wonder how much it’ll take with reduced concurrency
g
Hi , @Евгений Шишкин
Copy code
parallel_fragment_exec_instance_num=1,max_parallel_scan_instance_num=-1,pipeline_dop=0,
Total: 12s115ms
е
ok, so auto DegreeOfParallelism is 48 LOCAL_SORT_SINK is fast, LOCAL_MERGE_SOURCE is still slow to merge 3kk rows @Kevin Cai any ideas why merge is so slow?
👀 1
LOCAL_MERGE_SOURCE (plan_node_id=17): CommonMetrics: - OperatorTotalTime: 10s659ms - OutputChunkBytes: 1.302 GB - PullChunkNum: 863 - PullRowNum: 3.362M (3362123) - PullTotalTime: 10s658ms ah, so 10s is waiting for something
@guicheng.cai can you run the query with
explain analyze
so that we dont wait for the network?
g
е
yeah, LOCAL_MERGE_SOURCE PullTotalTime: 10s828ms no idea why is it so slow
@guicheng.cai can you try with different dop like 16,8,4,2 to see how it relates?
k
1. large final output, the result itself will take time transferring from FE to mysql client. try do it with
create table xxx as select ...
to save the selected result to a table and see how much time it will cost. 2. global order by in the final result is costy due to single-threaded merge of the final 3.3 million records. Have a try remove the
order by
, if the query costs changes.
g
Hi @Kevin Cai Thank you for your reply. 1、I have a question regarding the time consumption of LOCAL_MERGE_SOURCE. Is it related to the data transfer from the FE to the MySQL client? Moreover, since the transfer from the FE to the MySQL client is local, it shouldn’t take much time, right? Similarly, when executing an SQL query via clickhouse-client, the results also need to be transmitted from the ClickHouse server to the clickhouse-client. 2、It is to remove the "ORDER BY
日期
DESC, device;" at the end of SQL?
k
1. mysql protocol is not efficient for large data set transfer. 2. yes
👌 1
g
Hi @Евгений Шишкин Thank you for your support. Set the pipeline_dop values to 16,8,4,2 and have a try ?
Hi @Kevin Cai 1、Try do it with
create table xxx as select ...
to save the selected result to a table , and the query profile as follow:
Copy code
Query:
  Summary:
     - Query ID: 019ae236-e105-7a10-99fa-7e860e50d692
     - Start Time: 2025-12-03 03:17:18
     - End Time: 2025-12-03 03:17:33
     - Total: 15s192ms
     - Query Type: Query
     - Query State: Finished
     - StarRocks Version: 4.0.1-cd9df36
     - User: root
     - Default Db
     - Sql Statement: CREATE TABLE trancare_ads.ads_perf_lch_google_app_launch_stage_di_tmp_test 
PROPERTIES ("replication_num" = "1") 
AS
SELECT 
    ta.tos AS tos,
    ta.rom_vr AS rom_vr,
    ta.os_vr AS os_vr,
    ta.device AS device,
    ta.brand AS brand,
    ta.cpu AS cpu,
 ...
       
 LOCAL_MERGE_SOURCE (plan_node_id=17):
          CommonMetrics:
             - OperatorTotalTime: 11s893ms
             - OutputChunkBytes: 1.302 GB
             - PullChunkNum: 832
             - PullRowNum: 3.362M (3362123)
             - PullTotalTime: 11s892ms
             - PushChunkNum: 0
             - PushRowNum: 0
             - PushTotalTime: 0ns
2、Removing the "ORDER BY
日期
DESC, device;" at the end of SQL, The executed query profile is shown in the attachment. By the way, the performance has indeed improved a lot after the removal of "order by", but in actual business applications, "order by" may be required. How can this be optimized?
k
It is not efficient to unload data from starrocks using mysql protocol directly with global order by for a large dataset. And I suspect this is not an apple-to-apple comparison between SR mysql client and clickhouse-client. try a different scenario if do the performance comparison.
g
Hi @Евгений Шишкин @Kevin Cai pipeline_dop = 16 :
Copy code
- Total: 9s63ms  
        LOCAL_MERGE_SOURCE (plan_node_id=17):
          CommonMetrics:
             - OperatorTotalTime: 7s460ms
             - OutputChunkBytes: 1.302 GB
             - PullChunkNum: 832
             - PullRowNum: 3.362M (3362123)
             - PullTotalTime: 7s460ms
pipeline_dop = 8:
Copy code
- Total: 7s602ms
        LOCAL_MERGE_SOURCE (plan_node_id=17):
          CommonMetrics:
             - OperatorTotalTime: 5s597ms
             - OutputChunkBytes: 1.302 GB
             - PullChunkNum: 824
             - PullRowNum: 3.362M (3362123)
             - PullTotalTime: 5s597ms
pipeline_dop = 4:
Copy code
- Total: 7s19ms
        LOCAL_MERGE_SOURCE (plan_node_id=17):
          CommonMetrics:
             - OperatorTotalTime: 3s774ms
             - OutputChunkBytes: 1.302 GB
             - PullChunkNum: 824
             - PullRowNum: 3.362M (3362123)
             - PullTotalTime: 3s774ms
pipeline_dop = 2:
Copy code
- Total: 10s571ms
        LOCAL_MERGE_SOURCE (plan_node_id=17):
          CommonMetrics:
             - OperatorTotalTime: 5s478ms
             - OutputChunkBytes: 1.302 GB
             - PullChunkNum: 823
             - PullRowNum: 3.362M (3362123)
             - PullTotalTime: 5s478ms
By the way, shouldn't there be a cache after the first selection? Why does it take the same time for the same environment and query conditions to execute each time?
е
it seems to me that LOCAL_MERGE_SOURCE have trouble effectively merging sorted chunks, and optimal dop of 4 here proves it
g
Hi @Евгений Шишкин Regarding this issue, is it present in other versions as well? Additionally, given that the server hosting StarRocks has 96 CPU cores, why is it not possible to fully leverage the available resources—through parameters such as
parallel_fragment_exec_instance_num
and `pipeline_dop`—to achieve optimal query performance?
е
as far as i see, this query is bottlenecked by merging of sorter chunks, it is single process that needs to gather all the results. and here you can see that it is best to do it with pipeline_dop = 4 i dont know why parallel merge is not kicking in or how to speed up the merge
g
Hi @Евгений Шишкин Thank you for your analysis. I understand that the query bottleneck lies in the merging of sorted chunks and that the optimal
pipeline_dop
appears to be 4 in this case. Could you please advise if there is someone in the community who specializes in this area — particularly regarding LOCAL_MERGE_SOURCE performance and parallel merge mechanisms? If possible, I would appreciate an introduction or if you could forward this case to them for further insight on how to optimize or resolve the merge speed issue. We have already tried adjusting
parallel_fragment_exec_instance_num
and
pipeline_dop
, but it seems we are still not achieving the expected parallelism on a 96-core server. Any guidance on how to better utilize system resources or configure parallel merging would be very helpful.
е
@guicheng.cai i tried to do a repro, with the help on claude i made create table and insert statements and on my sr3.3 i get parallel merge i pasted code to https://www.paste.org/129684
basically i get 5s for query, 3 of which is mysql protocol conversion. this is 8 core machine r6id.2xlarge
🙌 1
g
Does the single architecture itself have no advantages? If I set up a cluster, will the overall performance be more advantageous?
е
multinode would introduce network transfer overhead
on my test instance from main branch the simplest order by uses LOCAL_MERGE_SOURCE, while on 3.3 it uses parallel there is a regression somewhere
possible regression is commit 0468393d84, will check later
🙌 1
👋 1
g
Hi @Евгений Шишкин Thank you for the quick investigation and sharing these findings. Is there a known workaround or fix planned for this problem? I'm so happy to help test any potential patches or configurations. Thanks a lot.
е
i’ll retest with that commit reverted
👌 1
nope, with commit 0468393d84 reverted still get LOCAL_MERGE_SOURCE
hmm, for iceberg it is single threaded and for native table it is PARALLEL_MERGE_SOURCE
🤔 1
😀 1
ok, the iceberg is different issue due to union node of eq deletes testing original query https://www.paste.org/129684 with patch reverted i get and set enable_parallel_merge = false | └──SORT (id=15) [ROW_NUMBER, SORT] | | │ Estimates: [row: 243000, cpu: 81645631.48, memory: 81645631.48, network: 81645631.48, cost: 578003486.50] | | │ TotalTime: 2s106ms (35.86%) [CPUTime: 2s106ms] | | │ OutputRows: 2.400M (2400000) | | │ PeakMemory: ?, AllocatedMemory: ? | | │ OrderByExprs: [<slot 58> 58: date, <slot 3> 3: device] | | │ SubordinateOperators: | | │ GROUP_EXCHANGE | | │ LOCAL_EXCHANGE [null] | with true i get LOCAL_PARALLEL_MERGE_SOURCE | └──SORT (id=15) [ROW_NUMBER, SORT] | | │ Estimates: [row: 243000, cpu: 81645631.48, memory: 81645631.48, network: 81645631.48, cost: 578003486.50] | | │ TotalTime: 439.625ms (9.97%) [CPUTime: 439.625ms] | | │ OutputRows: 2.400M (2400000) | | │ PeakMemory: ?, AllocatedMemory: ? | | │ OrderByExprs: [<slot 58> 58: date, <slot 3> 3: device] | | │ SubordinateOperators: | | │ GROUP_EXCHANGE | | │ LOCAL_EXCHANGE [Passthrough] | with main i get | └──SORT (id=16) [ROW_NUMBER, SORT] | | │ Estimates: [row: 1, cpu: ?, memory: ?, network: ?, cost: 4337.0] | | │ TotalTime: 2s594ms (37.05%) [CPUTime: 2s594ms] | | │ OutputRows: 2.400M (2400000) | | │ PeakMemory: ?, AllocatedMemory: ? | | │ OrderByExprs: [<slot 58> 58: date, <slot 3> 3: device] | and LOCAL_MERGE_SOURCE so my conclusion is that something wrong with 0468393d84
after running analyze on all tables and executing query TWICE, switches it to parallel merge so the culprit is somethere in statistics logic
verified that iceberg without eqdeletes also need stats to turn on parallel merge
@Kevin Cai i was debugging iceberg with eq deletes and parallel sort after FE restart mysql> show variables like ‘enable_parallel_merge’; +-----------------------+-------+ | Variable_name | Value | +-----------------------+-------+ | enable_parallel_merge | true | +-----------------------+-------+ But BE does not see it enabled I20251204 142835.304095 126045939963456 topn_node.cpp:399] TopNNode::decompose_to_pipeline plan_node_id=9 __isset.enable_parallel_merge=1 enable_parallel_merge_value=0 ordering_exprs_count=2 need_merge=1 enable_parallel_merge=0 If i set it forcefully, BE sees it mysql> set enable_parallel_merge = true; I20251204 142919.729901 126045948356160 topn_node.cpp:399] TopNNode::decompose_to_pipeline plan_node_id=9 __isset.enable_parallel_merge=1 enable_parallel_merge_value=1 ordering_exprs_count=2 need_merge=1 enable_parallel_merge=1
g
Hi @Kevin Cai Do you have time to look at this problem? Hi @Евгений Шишкин What is our next plan? Is the 4.0.1 version stable?
е
i'll check the statistics logic later, it should enable parallel scan if there is no stats, but clearly dont
and there is some strange stuff with default variables not being set somehow