Skip to content

Commit 81ed531

Browse files
committed
Add a new method to QueryConditionCache that determines whether the cached
query conditions need to be updated based on changes to underlying data or configuration. This improves query performance by avoiding unnecessary cache rebuilds while ensuring data consistency when conditions change. The method also helps reduce unnecessary lock contention, improving concurrency in multi-threaded query environments. Performance improvements: - Reduces the "native_queued_spin_lock_slowpath" hotspot of entry->mutex from 76% to 1% with Clickbench Q10 on a 2 x 240 vCPUs system - Increases QPS for Q10 and Q11 by 85% and 89% respectively - Improves overall performance across 43 queries with a geometric mean gain of 8.1% Signed-off-by: Jiebin Sun <[email protected]> Reviewed-by: Wangyang Guo <[email protected]>
1 parent b884cb9 commit 81ed531

File tree

2 files changed

+47
-0
lines changed

2 files changed

+47
-0
lines changed

src/Interpreters/Cache/QueryConditionCache.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,34 @@ QueryConditionCache::QueryConditionCache(const String & cache_policy, size_t max
1818
{
1919
}
2020

21+
inline bool QueryConditionCache::needUpdate(const std::shared_ptr<Entry> & entry, const MarkRanges & mark_ranges, size_t marks_count, bool has_final_mark) const
22+
{
23+
// If no marks to process, we may only need to update the final mark
24+
if (mark_ranges.empty()) {
25+
// Only acquire the lock and check final mark when has_final_mark is true
26+
std::shared_lock read_lock(entry->mutex);
27+
// Return true (update needed) only if final mark needs to be set to false
28+
return has_final_mark && entry->matching_marks[marks_count - 1];
29+
}
30+
else {
31+
// Acquire shared lock for read access to the matching_marks vector
32+
std::shared_lock read_lock(entry->mutex);
33+
34+
// Check if any mark within the ranges is still true
35+
for (const auto & mark_range : mark_ranges) {
36+
if (std::find(
37+
entry->matching_marks.begin() + mark_range.begin,
38+
entry->matching_marks.begin() + mark_range.end,
39+
true) != (entry->matching_marks.begin() + mark_range.end)) {
40+
return true; // Found at least one true mark in range, need update
41+
}
42+
}
43+
44+
// If all marks in ranges are already false, check if final mark needs update
45+
return has_final_mark && entry->matching_marks[marks_count - 1];
46+
}
47+
}
48+
2149
void QueryConditionCache::write(
2250
const UUID & table_id, const String & part_name, size_t condition_hash, const String & condition,
2351
const MarkRanges & mark_ranges, size_t marks_count, bool has_final_mark)
@@ -27,6 +55,10 @@ void QueryConditionCache::write(
2755
auto load_func = [&](){ return std::make_shared<Entry>(marks_count); };
2856
auto [entry, inserted] = cache.getOrSet(key, load_func);
2957

58+
// Skip update if not needed - optimization to avoid unnecessary locks and updates
59+
if (!needUpdate(entry, mark_ranges, marks_count, has_final_mark))
60+
return;
61+
3062
std::lock_guard lock(entry->mutex);
3163

3264
chassert(marks_count == entry->matching_marks.size());

src/Interpreters/Cache/QueryConditionCache.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,21 @@ class QueryConditionCache
7171
size_t operator()(const Entry & entry) const;
7272
};
7373

74+
/**
75+
* Check if we need to update the cache entry.
76+
* This function determines whether a cache update is necessary by examining:
77+
* 1. Whether the mark ranges are empty
78+
* 2. Whether marks in specified ranges are already set to false
79+
* 3. Whether the final mark (if applicable) is already set correctly
80+
*
81+
* @param entry The cache entry to check
82+
* @param mark_ranges The ranges of marks to potentially update
83+
* @param marks_count Total number of marks in the entry
84+
* @param has_final_mark Flag indicating if the final mark needs special handling
85+
* @return true if an update is needed, false if we can skip the update
86+
*/
87+
inline bool needUpdate(const std::shared_ptr<Entry> & entry, const MarkRanges & mark_ranges, size_t marks_count, bool has_final_mark) const;
88+
7489
public:
7590
using Cache = CacheBase<Key, Entry, KeyHasher, QueryConditionCacheEntryWeight>;
7691

0 commit comments

Comments
 (0)