go-mysql-server
go-mysql-server copied to clipboard
proposal: Refactor Indexed Table Access
This is a design proposal to refactor the way indexed table access works and what abstractions are exposed to Integrators:
The core change comes to sql.IndexLookup which will now be a concrete type constructed by the engine, not integrators:
-type IndexLookup interface {
- fmt.Stringer
+type IndexLookup struct {
+ Str string
// Index returns the index that created this IndexLookup.
- Index() Index
+ Index Index
// Ranges returns each Range that created this IndexLookup.
- Ranges() RangeCollection
+ Ranges RangeCollection
}
This implies removing sql.Index.NewLookup, which will be replaced by an integrator method to indicate whether a given index can support a given lookup:
type Index interface {
// ID returns the identifier of the index.
ID() string
// Database returns the database name this index belongs to.
Database() string
// Table returns the table name this index belongs to.
Table() string
// Expressions returns the indexed expressions. If the result is more than
// one expression, it means the index has multiple columns indexed. If it's
// just one, it means it may be an expression or a column.
Expressions() []string
// IsUnique returns whether this index is unique
IsUnique() bool
// Comment returns the comment for this index
Comment() string
// IndexType returns the type of this index, e.g. BTREE
IndexType() string
// IsGenerated returns whether this index was generated. Generated indexes
// are used for index access, but are not displayed (such as with SHOW INDEXES).
IsGenerated() bool
- // NewLookup returns a new IndexLookup for the ranges given. Ranges represent filters over columns. Each Range
- // is ordered by the column expressions (as returned by Expressions) with the RangeColumnExpr representing the
- // searchable area for each column expression. Each Range given will not overlap with any other ranges. Additionally,
- // all ranges will have the same length, and may represent a partial index (matching a prefix rather than the entire
- // index). If an integrator is unable to process the given ranges, then a nil may be returned. An error should be
- // returned only in the event that an error occurred.
- NewLookup(ctx *Context, ranges ...Range) (IndexLookup, error)
+ // SupportsLookup returns true if the Index supports |lookup|.
+ SupportsLookup(ctx *Context, lookup IndexLookup) (bool, error)
// ColumnExpressionTypes returns each expression and its associated Type. Each expression string should exactly
// match the string returned from Index.Expressions().
ColumnExpressionTypes(ctx *Context) []ColumnExpressionType
}
Finally, IndexedTable and IndexAddressableTable collapse into a single interface that exposed a set of Index definitions, and an AccessIndex() method that asks for a RowIter given an IndexLookup:
diff --git a/sql/core.go b/sql/core.go
index d0b3ba54..8ed56b1c 100644
--- a/sql/core.go
+++ b/sql/core.go
@@ -430,28 +430,14 @@ type IndexColumn struct {
// speed up execution of queries that reference those columns. Unlike DriverIndexableTable, IndexedTable doesn't need a
// separate index driver to function.
type IndexedTable interface {
- IndexAddressableTable
// GetIndexes returns all indexes on this table.
GetIndexes(ctx *Context) ([]Index, error)
-}
-
-// IndexAddressable provides a Table that has its row iteration restricted to only the rows that match the given index
-// lookup.
-type IndexAddressable interface {
- // WithIndexLookup returns a version of the table that will return only the rows specified by the given IndexLookup,
- // which was in turn created by a call to Index.Get() for a set of keys for this table.
- WithIndexLookup(IndexLookup) Table
-}
-
-// IndexAddressableTable is a table that can restrict its row iteration to only the rows that match the given index
-// lookup.
-type IndexAddressableTable interface {
- Table
- IndexAddressable
+ // AccessIndex constructs a RowIter from an IndexLookup.
+ AccessIndex(ctx *Context, lookup IndexLookup) (RowIter, error)
}
@max-hoffman @zachmu @Hydrocharged @reltuk interested to hear your thoughts
I'm in favor of this.
IndexLookup shouldn't have Str, it should still implement fmt.Stringer
IndexedTable should either embed sql.Table, or else just become IndexAddressable
AccessIndex should be IndexedRowIter
I’m also in favor of this. Zach’s additional comments also seem reasonable, and I have no additional comments myself.
My only cons are: I don't know if this will be easy to implement given our index caching and the weirdness with dolt history tables, and I have issues in my queue that are correctness and perf problems, which I would think take precedence over interface refactoring.
In general seems reasonable.
Table currently doesn't have a RowIter() method. Seems like this should be IndexedPartitions(*Context, IndexLookup) (PartitionIter, error), and PartitionRows() gets used for both types of partitions?
addressed in https://github.com/dolthub/go-mysql-server/pull/1183