@@ -7760,7 +7760,7 @@ void MergeTreeData::addPartContributionToColumnAndSecondaryIndexSizesUnlocked(co
77607760 primary_index_size.add(part->getIndexSizeFromFile());
77617761}
77627762
7763- IStorage::ColumnSizeByName MergeTreeData::getColumnSizes(const Names & columns) const
7763+ IStorage::ColumnSizeByName MergeTreeData::getColumnSizes(const Names & columns, bool calculate_subcolumn_sizes ) const
77647764{
77657765 auto result = getColumnSizes();
77667766
@@ -7777,12 +7777,36 @@ IStorage::ColumnSizeByName MergeTreeData::getColumnSizes(const Names & columns)
77777777 if (subcolumn_names.empty())
77787778 return result;
77797779
7780- /// For each requested column that is a subcolumn and not already in the result,
7781- /// aggregate its size across all active parts using getSubcolumnSize.
7782- /// This gives the correct on-disk size for subcolumns based on required substreams.
7783- auto parts_lock = readLockParts();
7784- auto committed_parts_range = getDataPartsStateRange(DataPartState::Active);
7785- for (const auto & part : committed_parts_range)
7780+ /// When exact subcolumn sizes are disabled, approximate each subcolumn with its whole top-level
7781+ /// column size (already in result), resolved from metadata without locking parts.
7782+ if (!calculate_subcolumn_sizes)
7783+ {
7784+ auto metadata_snapshot = getInMemoryMetadataPtr(getContext(), false);
7785+ const auto & storage_columns = metadata_snapshot->getColumns();
7786+ for (const auto & col_name : subcolumn_names)
7787+ {
7788+ auto column = storage_columns.tryGetColumnOrSubcolumn(GetColumnsOptions::All, col_name);
7789+ if (column && column->isSubcolumn())
7790+ {
7791+ if (auto it = result.find(column->getNameInStorage()); it != result.end())
7792+ result[col_name] = it->second;
7793+ }
7794+ }
7795+
7796+ return result;
7797+ }
7798+
7799+ /// Exact subcolumn sizes are derived per active part from the required substreams.
7800+ /// Snapshot the parts under the lock and release it before the per-part size calculation,
7801+ /// which reads part-local state and would otherwise block part commits and merges.
7802+ DataPartsVector parts;
7803+ {
7804+ auto parts_lock = readLockParts();
7805+ auto committed_parts_range = getDataPartsStateRange(DataPartState::Active);
7806+ parts.assign(committed_parts_range.begin(), committed_parts_range.end());
7807+ }
7808+
7809+ for (const auto & part : parts)
77867810 {
77877811 for (const auto & col_name : subcolumn_names)
77887812 {
0 commit comments