-
-
Notifications
You must be signed in to change notification settings - Fork 238
Index optimize extension with dynamic index support in embed db #2036
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
Hi @coyzeng, thank you for taking the time to contribute this interface suggestion. We have also been spinning with some ideas of how to sharpen up the indexed access interface. The current way we support this is by having an indexable table source |
I have some logic table, they work with dynamic index, like virtual index. If query condition can not hit the fixed index, it will scan all rows of the table. Dynamic index work without scan all rows of the table. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The interceptor chain is interesting and could be useful, but I have a couple suggestions on it.
The index change I don't think is necessary. Take a look at my comments and see if they make sense.
server/extension.go
Outdated
| c Chain | ||
| } | ||
|
|
||
| func (that *chainInterceptor) ComQuery(c *mysql.Conn, query string, callback func(res *sqltypes.Result, more bool) error) error { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Name the receiver ci to match package style
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
sql/analyzer/index_dyn.go
Outdated
|
|
||
| const DynIndex = "DYN" | ||
|
|
||
| type DynamicIndex interface { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think you want or need a new interface to accomplish your goals here. If you want to implement a custom index type that matches some subset of expressions, your best bet is for your table implementation to return N indexes, one for each combination of expressions you are capable of indexing. This is how Dolt originally implemented index prefix matching before we implemented it natively in go-mysql-server.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's difficult to match any index without query condition, 'IndexAddressable' not support query condition in go-mysql-server now. This solution is the simplest way to implement some index feature without code changes. Virtual table need dynamic index to skip scan all rows of table.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If use'IndexAddressable' for table implementation, it need build too many complex index to match query. The number of columns combinations is very big and complex.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One thing we could maybe support is a new interface that does something like this:
type IndexSearchable interface {
IndexWithPrefix([]string) []sql.Index
}You would switch for this type before falling back to the old expression checking pattern.
We are going to delete indexAnalyzer and all of the existing index matching code shortly, to be replaced with a very different way of representing indexes and expressions. New index matching interfaces needs to be compatible with how this logic will work in a couple months
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Max's suggestion sounds reasonable. The rest of the PR looks reasonable if you make that change.
Thanks for the contribution!
server/server.go
Outdated
| } | ||
|
|
||
| func newServerFromHandler(cfg Config, e *sqle.Engine, sm *SessionManager, handler mysql.Handler) (*Server, error) { | ||
| handler = withChain(handler) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be a configuration option on cfg, not hardcoded here. We don't want the interceptor chain installed by default (even with an empty chain)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changes look good except for the new interface. Implement Max's suggestion and we'll merge it in.
sql/analyzer/index_dyn.go
Outdated
|
|
||
| const DynIndex = "DYN" | ||
|
|
||
| type DynamicIndex interface { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Max's suggestion sounds reasonable. The rest of the PR looks reasonable if you make that change.
Thanks for the contribution!
I have implemented Max's suggestion. But I'm not sure it's the best way. Max says indexAnalyzer will be remove shortly. I also want to create another PR for mysql fully homomorphic encryption pluggable expression support. Which make go-mysql can work on multi party data with privacy computing. |
|
This is what the index scan rewrite will look like, as a reference #2093. It will take 4-5 more PRs for this to replace the current form, but I've thought about it more thoroughly now. The interface you're suggesting would fork the implementation based on whether you want a costed approach to choosing indexes, or defer to the database to choose its own preferred index. All I need is the hook for 1) checking if the database wants to override statistical index checking, and 2) a method that gives the table a list of equality filters, and returns a type IndexSearchable interface {
SkipIndexCosting() bool
IndexWithPrefix([]string) sql.IndexLookup
}Supporting range filters might need a different interface. Just trying to make sure these two PRs converge in a way that doesn't break compatibility for you. |
I redeclare IndexSearchable as below and make a slight edit. This is the minimal edit before #2093 draft merged. type IndexSearchable interface {
// SkipIndexCosting will choose the database preferred index if return true.
SkipIndexCosting() bool
// IndexWithPrefix returns an array of this table's Indexes that matched with prefix.
IndexWithPrefix(ctx *Context, expressions []string) (Index, error)
// IndexWithExpression returns an array of this table's Indexes that matched with expression.
IndexWithExpression(ctx *Context, expressions []Expression) (Index, error)
} |
|
I finished up the indexScan rewrite today, and I ported your interface suggestion here #2125. Can you take a look and tell me whether this works for you? Reusing engine logic and implementing You could edit and send back a different PR if you need more functionality. Either way, it might be easier to separate the interceptor chain and index changes into two different PRs. |
In my case, my mysql server support multi different table, like API table, private table etc..., some table index must be dynamic for support index optimize with complex condition.