Cache queries on whether they are direct-to-shard + SQL#1027
Conversation
This change allows the query rewriter to safely modify its behavior for direct-to-shard queries, and skip rewrite steps that are only needed for cross-shard queries. Though this commit does not take advantage of this, future changes will require this behavior and changing the cache key required enough code to justify being pulled into its own commit. The signature of Map::get and Borrow means this needs a bit more boilerplate than I would have liked. There is no way to implement Borrow<(str, _)> for (String, _) (or any other owned/ref types). Instead we have to erase the types to a trait object so we can get individual references to the fields when we need them for comparison and hashing. This trait is implemented for any combination of values/refs, and a special case for (Arc<A>, B). If in the future this trait is needed with additional pointer types, or Arc in the right position, additional manual impls will need to be added.
This comment has been minimized.
This comment has been minimized.
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
Based on my reading, this change only actually detects if the user passed in |
While we can't completely treat direct-to-shard queries the same as unsharded queries, we can at least skip certain parts of the rewriter. In particular, the aggregate rewrite does some extra work that will never be needed on direct-to-shard, and skipping it allows us to error on aggregate functions we don't support without breaking the very niche case of an unsupported aggregate function being used by a user only in direct-to-shard queries. Actually implementing this was a bit of a PITA. Since we cache the AST after the rewriter mutates it, as opposed to just the results of pg_query::parse, we needed to add whether the query is direct-to-shard to the cache key (#1027) The natural place to exit early is the same place we do the "skip this if the schema only has one shard", but that information was previously lost all the way up at the cache impl, so we needed to pass this information through quite a few levels of indirection. Ultimately I think we need to separate out parsing from rewriting more concretely, and structure rewriting much differently with a better structured context. However, as I work towards being ready to do that larger restructuring, putting this where it's most natural to make the dependency graph clear seems like the right short-term path forward.
This change allows the query rewriter to safely modify its behavior for direct-to-shard queries, and skip rewrite steps that are only needed for cross-shard queries.
Though this commit does not take advantage of this, future changes will require this behavior and changing the cache key required enough code to justify being pulled into its own commit.
The signature of Map::get and Borrow means this needs a bit more boilerplate than I would have liked. There is no way to implement Borrow<(str, _)> for (String, _) (or any other owned/ref types). Instead we have to erase the types to a trait object so we can get individual references to the fields when we need them for comparison and hashing.
This trait is implemented for any combination of values/refs, and a special case for (Arc, B). If in the future this trait is needed with additional pointer types, or Arc in the right position, additional manual impls will need to be added.