Add `cachepath` Attribute to Query Tag for Efficient Cache Management

Summary

Add a cachepath attribute to <cfquery> and queryExecute() that prepends a custom prefix to auto-generated cache IDs, enabling efficient key-based cache management operations.

Problem Statement

Current Performance Issue

The existing tags attribute for query cache management stores tags in cache values, not keys. This means operations like cacheClear(["tagname"], "query") must:

  1. Retrieve all cache keys from the store (e.g., Redis)
  2. Read the complete value of every cached object
  3. Deserialize each object to check for matching tags
  4. Delete matching entries

Impact: In a Redis cache with 10,000+ cached queries, clearing by tag requires reading and deserializing all 10,000 objects, taking several seconds and blocking the application during the scan.

Auto-Generated Cache IDs

Additionally, Lucee auto-generates cache IDs as hashes based on SQL/datasource/credentials. This makes it impossible to:

  • Selectively clear specific cached queries
  • Check if a query is cached without executing it
  • Debug cache contents effectively

Proposed Solution

Add a cachepath attribute that prepends a custom string to the auto-generated cache ID:

<cfquery name="users" datasource="myDB"
         cachepath="users:active:"
         cachedwithin="#createTimeSpan(0,1,0,0)#">
    SELECT * FROM users WHERE active = 1
</cfquery>

Result: Cache ID becomes "users:active:A7F2E1C9D..." instead of just "A7F2E1C9D..."

Key Benefits

  1. Performance: Key-based cache clearing is O(k) where k = matching keys, vs O(n) where n = ALL cached objects
  2. Constant-time operations: Performance independent of total cache size—only matching keys are read
  3. Preserves uniqueness: Prepending maintains SQL/datasource hash, preventing conflicts
  4. Known key prefixes: Developers can use predictable prefixes for cache management
  5. Backward compatible: Zero impact on existing code

Use Case

1. Clear All User Queries


<cfquery cachepath="users:" cachedwithin="...">SELECT...</cfquery>

<!--- Clear only user queries, skip others --->

<cfset cacheRemove("users:*")> <!--- Fast: no deserialization --->

Compatibility

  • Fully backward compatible—existing queries work unchanged

  • Works with all cache handlers (RAM, Redis, EHCache, Memcached)

  • No breaking changes to cache ID generation for queries without cachepath

2 Likes

Just for reference, Ive already made the required changes in the Lucee code locally and tested with my app (and a bunch of Testbox tests). Its a simple change to codebase, so its ready to go if approved :slight_smile:

I really like it.
I’ve developed a small class that acts as a proxy for the Lucee cache that does just that: it adds the concept of “scope” to the cache.

getCacheManager().put/get( key, scope, value );

For this reason, I never use “cachedwithin” but instead add the query directly to the cache:

cache.put( "userGet_" & Hash( user.id ), "cfquery:userGet", local.userGetQuery );

Your concept of “path” (or prefix) seems much more flexible to me.

1 Like

Thanks @Roberto_Marzialetti
I actually prefer cacheprefix as the attribute name, it makes more sense.
I’ll update the proposal.
Cheers!

Edit, I cannot figure out how to edit the original post :grimacing:

@Zackster I was about to create an LDEV ticket, but the note said ‘Once the issue has been verified, one of the Lucee team will ask you to file an issue’. :slight_smile:

@dman1 , Could you please go ahead and create the LDEV ticket for this and commit your changes?
I’d really appreciate it. I’m happy to contribute with further testing if needed.

1 Like

Actually there’s already cacheRegion in ACF which we don’t support as of yet

https://luceeserver.atlassian.net/browse/LDEV-4130

@Zackster I understood that to be the cache that it would store in, like an override for the default query cache, in case you had multiple query caches like ‘userquerycache’ and ‘dataquerycache’ setup in Lucee and you want to tell the query which one to use?

Updated to cacheprefix at Jira

please target the 7.0 branch, 6.2 is in maintenance mode now and only getting bug fixes

Done.