From a7557283e245cc14a38fb2d5a09b4b5397e409fd Mon Sep 17 00:00:00 2001 From: winfredLIN Date: Fri, 8 Dec 2023 15:18:41 +0800 Subject: [PATCH] feat: increase coverage of three star advisor --- sqle/driver/mysql/advisor.go | 524 +++++++++++++++++++---------------- 1 file changed, 285 insertions(+), 239 deletions(-) diff --git a/sqle/driver/mysql/advisor.go b/sqle/driver/mysql/advisor.go index 33f439f420..5ac196fd5f 100644 --- a/sqle/driver/mysql/advisor.go +++ b/sqle/driver/mysql/advisor.go @@ -172,6 +172,93 @@ func (c columnMap) delete(col *ast.ColumnNameExpr) { delete(c, col.Name.Name.L) } +type columnWithSelectivity struct { + columnName *ast.ColumnNameExpr + selectivity float64 +} + +type columnsWithSelectivity []columnWithSelectivity + +type columnGroup struct { + columnsWithSelectivity + columnMap +} + +func newColumnGroup() columnGroup { + return columnGroup{ + columnsWithSelectivity: make(columnsWithSelectivity, 0), + columnMap: make(columnMap), + } +} + +func (g *columnGroup) setSelectivity(selectivityMap map[string] /*column name*/ float64) { + var columnName string + for i := range g.columnsWithSelectivity { + columnName = g.columnsWithSelectivity[i].columnName.Name.Name.L + g.columnsWithSelectivity[i].selectivity = selectivityMap[columnName] + } +} + +func (g columnGroup) len() int { + return len(g.columnMap) +} + +func (g *columnGroup) sort() { + sort.Sort(g.columnsWithSelectivity) +} + +func (g columnGroup) has(col *ast.ColumnNameExpr) bool { + _, exist := g.columnMap[col.Name.Name.L] + return exist +} + +func (g *columnGroup) add(col *ast.ColumnNameExpr) { + if _, exist := g.columnMap[col.Name.Name.L]; exist { + // 不重复添加 + return + } + g.columnMap.add(col) + g.columnsWithSelectivity = append(g.columnsWithSelectivity, columnWithSelectivity{columnName: col}) +} + +func (g *columnGroup) replace(newColumn columnWithSelectivity, index int) { + oldColumn := g.columnsWithSelectivity[index] + g.columnsWithSelectivity[index] = newColumn + g.columnMap.delete(oldColumn.columnName) + g.columnMap.add(newColumn.columnName) +} + +func (g *columnGroup) delete(col *ast.ColumnNameExpr) { + g.columnMap.delete(col) + var index int + for index = range g.columnsWithSelectivity { + if g.columnsWithSelectivity[index].columnName == col { + break + } + } + g.columnsWithSelectivity = append(g.columnsWithSelectivity[:index], g.columnsWithSelectivity[index:]...) +} + +func (g columnGroup) stringSlice() []string { + indexedColumn := make([]string, 0, len(g.columnMap)) + for _, column := range g.columnsWithSelectivity { + indexedColumn = append(indexedColumn, column.columnName.Name.Name.L) + } + return indexedColumn +} + +func (c columnsWithSelectivity) Len() int { + return len(c) +} + +func (c columnsWithSelectivity) Less(i, j int) bool { + return c[i].selectivity > c[j].selectivity +} + +func (c columnsWithSelectivity) Swap(i, j int) { + c[i], c[j] = c[j], c[i] +} + type CreateIndexAdvisor interface { GiveAdvices() []*OptimizeResult } @@ -179,23 +266,23 @@ type CreateIndexAdvisor interface { type threeStarIndexAdvisor struct { sqlContext *session.Context log *logrus.Entry - drivingTableSource *ast.TableSource // 驱动表的TableSource - drivingTableColumn *columnInSelect // 经过解析的驱动表的列 - drivingTableCreateStmt *ast.CreateTableStmt // 驱动表的建表语句 - originNode ast.Node // 原SQL的节点 - maxColumns int // 复合索引列的上限数量 - possibleColumns columnMap // SQL语句中可能作为索引的备选列 - columnLastAdd columnMap // 最后添加的列,例如:非等值列 - columnShouldNotAdd columnMap // 不该添加的列,例如:类型不适合作为索引的列、单列主键列 - columnHasAdded columnMap // 已经添加的列 - adviceColumns []columnWithSelectivity // 给出建议的列 + drivingTableSource *ast.TableSource // 驱动表的TableSource + drivingTableColumn *columnInSelect // 经过解析的驱动表的列 + drivingTableCreateStmt *ast.CreateTableStmt // 驱动表的建表语句 + originNode ast.Node // 原SQL的节点 + maxColumns int // 复合索引列的上限数量 + usingOr bool // 使用了或条件 + possibleColumns columnGroup // SQL语句中可能作为索引的备选列 + columnLastAdd columnGroup // 最后添加的列,例如:非等值列 + columnShouldNotAdd columnGroup // 不该添加的列,例如:类型不适合作为索引的列、单列主键列 + adviceColumns columnGroup } type columnInSelect struct { - equalColumnInWhere columnsWithSelectivity - unequalColumnInWhere columnsWithSelectivity - columnInOrderBy columnsWithSelectivity - columnInFieldList columnsWithSelectivity + equalColumnInWhere columnGroup + unequalColumnInWhere columnGroup + columnInOrderBy columnGroup + columnInFieldList columnGroup } func newThreeStarIndexAdvisor(ctx *session.Context, log *logrus.Entry, originNode ast.Node, params params.Params) CreateIndexAdvisor { @@ -204,16 +291,20 @@ func newThreeStarIndexAdvisor(ctx *session.Context, log *logrus.Entry, originNod maxColumns = MAX_INDEX_COLUMN_DEFAULT_VALUE } return &threeStarIndexAdvisor{ - sqlContext: ctx, - log: log, - originNode: originNode, - maxColumns: maxColumns, - drivingTableColumn: &columnInSelect{}, - columnLastAdd: make(columnMap), - possibleColumns: make(columnMap), - columnHasAdded: make(columnMap, maxColumns), - columnShouldNotAdd: make(columnMap), - adviceColumns: make([]columnWithSelectivity, 0), + sqlContext: ctx, + log: log, + originNode: originNode, + maxColumns: maxColumns, + drivingTableColumn: &columnInSelect{ + equalColumnInWhere: newColumnGroup(), + unequalColumnInWhere: newColumnGroup(), + columnInOrderBy: newColumnGroup(), + columnInFieldList: newColumnGroup(), + }, + columnLastAdd: newColumnGroup(), + possibleColumns: newColumnGroup(), + columnShouldNotAdd: newColumnGroup(), + adviceColumns: newColumnGroup(), } } @@ -240,7 +331,8 @@ func (a *threeStarIndexAdvisor) GiveAdvices() []*OptimizeResult { a.log.Logger.Warnf("extract column in select failed, sql:%s,err:%v", restore(a.originNode), err) return nil } - if len(a.possibleColumns) == 0 { + + if !a.canGiveAdvice() { return nil } err = a.fillColumnWithSelectivity() @@ -250,12 +342,12 @@ func (a *threeStarIndexAdvisor) GiveAdvices() []*OptimizeResult { } a.sortColumnBySelectivity() a.giveAdvice() - if util.IsIndex(a.columnHasAdded, a.drivingTableCreateStmt.Constraints) { + if util.IsIndex(a.adviceColumns.columnMap, a.drivingTableCreateStmt.Constraints) { return nil } return []*OptimizeResult{{ TableName: util.GetTableNameFromTableSource(a.drivingTableSource), - IndexedColumns: a.indexColumns(), + IndexedColumns: a.adviceColumns.stringSlice(), Reason: fmt.Sprintf("索引建议 | SQL:%s 中,根据三星索引设计规范", restore(a.originNode)), }} } @@ -268,177 +360,6 @@ func (a *threeStarIndexAdvisor) loadEssentials() (err error) { return nil } -func (a *threeStarIndexAdvisor) giveAdvice() { - // 加入WHERE等值条件中的列 - for _, column := range a.drivingTableColumn.equalColumnInWhere { - if len(a.adviceColumns) == a.maxColumns { - break - } - if a.shouldSkipColumn(column) { - continue - } - a.addColumn(column) - } - // 添加一个排序列 - if a.canAddOrderColumn() { - for _, column := range a.drivingTableColumn.columnInOrderBy { - if a.shouldSkipColumn(column) { - continue - } - if len(a.adviceColumns) < a.maxColumns { - a.addColumn(column) - } else if a.adviceColumns[len(a.adviceColumns)-1].selectivity < column.selectivity { - // 当建议的列已满,此时如果建议的列的最后一列的区分度小于排序列的区分度,则替换该列为排序列 - a.replaceColumn(column, len(a.adviceColumns)-1) - } - break - } - } - // 如果能够形成覆盖索引,则添加SELECT中的剩余列 - if a.canGiveCoverIndex() { - for _, column := range a.drivingTableColumn.columnInFieldList { - if len(a.adviceColumns) == a.maxColumns { - break - } - if a.shouldSkipColumn(column) { - continue - } - a.addColumn(column) - } - } - // 最后添加一列WHERE中的非等值列 - if a.canAddUnequalColumn() { - if len(a.drivingTableColumn.unequalColumnInWhere) > 0 { - a.addColumn(a.drivingTableColumn.unequalColumnInWhere[0]) - } - } -} - -func (a threeStarIndexAdvisor) shouldSkipColumn(column columnWithSelectivity) bool { - columnName := column.columnName.Name.Name.L - if _, exist := a.possibleColumns[columnName]; !exist { - // 跳过非备选列 - return true - } - if _, exist := a.columnHasAdded[columnName]; exist { - // 跳过已有列 - return true - } - if _, exist := a.columnLastAdd[columnName]; exist { - // 跳过最后添加的列 - return true - } - if _, exist := a.columnShouldNotAdd[columnName]; exist { - // 跳过不建议添加的列 - return true - } - return false -} - -func (a *threeStarIndexAdvisor) addColumn(column columnWithSelectivity) { - a.adviceColumns = append(a.adviceColumns, column) - a.columnHasAdded.add(column.columnName) -} - -func (a *threeStarIndexAdvisor) replaceColumn(newColumn columnWithSelectivity, index int) { - oldColumn := a.adviceColumns[index] - a.adviceColumns[index] = newColumn - a.columnHasAdded.delete(oldColumn.columnName) - a.columnHasAdded.add(newColumn.columnName) -} - -func (a threeStarIndexAdvisor) canAddOrderColumn() bool { - originNode, ok := a.originNode.(*ast.SelectStmt) - if !ok { - return false - } - if originNode.OrderBy == nil { - return false - } - if len(originNode.OrderBy.Items) == 0 { - return false - } - // 如果有多个不同方向的排序,则不将排序列放到索引中 - var firstOrder bool = originNode.OrderBy.Items[0].Desc - for _, col := range originNode.OrderBy.Items { - if col.Desc != firstOrder { - return false - } - } - // 如果排序列已在索引建议中则不添加 - for _, column := range a.drivingTableColumn.columnInOrderBy { - columnName := column.columnName.Name.Name.L - if _, exist := a.columnLastAdd[columnName]; exist { - continue - } - if _, exist := a.columnHasAdded[columnName]; exist { - return false - } - } - return true -} - -func (a threeStarIndexAdvisor) canAddUnequalColumn() bool { - return len(a.adviceColumns) < a.maxColumns -} - -func (a threeStarIndexAdvisor) canGiveCoverIndex() bool { - // 非等值列大于1时,覆盖索引走不到索引的最后一列,不添加覆盖索引 - if len(a.drivingTableColumn.unequalColumnInWhere) > 1 { - return false - } - // 当备选列大于索引列的上限时,覆盖索引不满足该限制,不添加覆盖索引 - if len(a.possibleColumns) > a.maxColumns { - return false - } - return true -} - -func (a threeStarIndexAdvisor) isColumnInDrivingTable(column *ast.ColumnNameExpr) bool { - if column.Name.Table.L == "" { - // 没有表名,说明只有一张表 - return true - } - return column.Name.Table.L == util.GetTableNameFromTableSource(a.drivingTableSource) -} - -func (a *threeStarIndexAdvisor) sortColumnBySelectivity() { - sort.Sort(a.drivingTableColumn.columnInOrderBy) - sort.Sort(a.drivingTableColumn.columnInFieldList) - sort.Sort(a.drivingTableColumn.unequalColumnInWhere) - sort.Sort(a.drivingTableColumn.equalColumnInWhere) -} - -func (a *threeStarIndexAdvisor) fillColumnWithSelectivity() error { - tableName, ok := a.drivingTableSource.Source.(*ast.TableName) - if !ok { - return fmt.Errorf("in three star advisor driving tableSource.Source is not ast.TableName") - } - columnNames := make([]string, 0, len(a.possibleColumns)) - for key := range a.possibleColumns { - columnNames = append(columnNames, key) - } - - selectivityMap, err := a.sqlContext.GetSelectivityOfColumns(tableName, columnNames) - if err != nil { - return err - } - // 填充驱动表中各列的列区分度 - for i := range a.drivingTableColumn.equalColumnInWhere { - a.drivingTableColumn.equalColumnInWhere[i].selectivity = selectivityMap[a.drivingTableColumn.equalColumnInWhere[i].columnName.Name.Name.L] - } - for i := range a.drivingTableColumn.columnInFieldList { - a.drivingTableColumn.columnInFieldList[i].selectivity = selectivityMap[a.drivingTableColumn.columnInFieldList[i].columnName.Name.Name.L] - } - for i := range a.drivingTableColumn.columnInOrderBy { - a.drivingTableColumn.columnInOrderBy[i].selectivity = selectivityMap[a.drivingTableColumn.columnInOrderBy[i].columnName.Name.Name.L] - } - for i := range a.drivingTableColumn.unequalColumnInWhere { - a.drivingTableColumn.unequalColumnInWhere[i].selectivity = selectivityMap[a.drivingTableColumn.unequalColumnInWhere[i].columnName.Name.Name.L] - } - return nil -} - /* 获取SELECT语句中: @@ -455,10 +376,10 @@ func (a *threeStarIndexAdvisor) extractColumnInSelect() error { if selectStmt.Where != nil { // 访问Where子句,解析并存储属于驱动表等值列和非等值列 selectStmt.Where.Accept(a) - for _, col := range a.drivingTableColumn.equalColumnInWhere { + for _, col := range a.drivingTableColumn.equalColumnInWhere.columnsWithSelectivity { a.possibleColumns.add(col.columnName) } - for _, col := range a.drivingTableColumn.unequalColumnInWhere { + for _, col := range a.drivingTableColumn.unequalColumnInWhere.columnsWithSelectivity { a.columnLastAdd.add(col.columnName) a.possibleColumns.add(col.columnName) } @@ -470,10 +391,7 @@ func (a *threeStarIndexAdvisor) extractColumnInSelect() error { if !a.isColumnInDrivingTable(col) { continue } - a.drivingTableColumn.columnInOrderBy = append( - a.drivingTableColumn.columnInOrderBy, - columnWithSelectivity{columnName: col}, - ) + a.drivingTableColumn.columnInOrderBy.add(col) a.possibleColumns.add(col) } } @@ -481,14 +399,19 @@ func (a *threeStarIndexAdvisor) extractColumnInSelect() error { if selectStmt.Fields != nil { // 遍历Select子句,存储其中属于驱动表的裸列 for _, field := range selectStmt.Fields.Fields { + + if field.WildCard != nil && field.WildCard.Table.String() == "" && field.WildCard.Schema.String() == "" { + // 如果是*则添加所有列 + for _, col := range a.drivingTableCreateStmt.Cols { + a.drivingTableColumn.columnInFieldList.add(&ast.ColumnNameExpr{Name: col.Name}) + } + continue + } if col, ok := field.Expr.(*ast.ColumnNameExpr); ok { if !a.isColumnInDrivingTable(col) { continue } - a.drivingTableColumn.columnInFieldList = append( - a.drivingTableColumn.columnInFieldList, - columnWithSelectivity{columnName: col}, - ) + a.drivingTableColumn.columnInFieldList.add(col) a.possibleColumns.add(col) } } @@ -507,16 +430,16 @@ func (a *threeStarIndexAdvisor) extractColumnInSelect() error { if primaryColumn != nil { primaryColumnName := primaryColumn.Name.L // 当主键不在备选列中时,不考虑该情况 - if _, exist := a.possibleColumns[primaryColumnName]; !exist { + if !a.possibleColumns.has(&ast.ColumnNameExpr{Name: primaryColumn}) { return nil } var orderByPrimaryKey bool // 当没有Order By时,按照主键排序,覆盖索引可以不包含主键 - if len(a.drivingTableColumn.columnInOrderBy) == 0 { + if a.drivingTableColumn.columnInOrderBy.len() == 0 { orderByPrimaryKey = true } // 当Order By主键的时候,按照主键排序,覆盖索引可以不包含主键 - if len(a.drivingTableColumn.columnInOrderBy) == 1 && a.drivingTableColumn.columnInOrderBy[0].columnName.Name.Name.L == primaryColumnName { + if a.drivingTableColumn.columnInOrderBy.len() == 1 && a.drivingTableColumn.columnInOrderBy.columnsWithSelectivity[0].columnName.Name.Name.L == primaryColumnName { orderByPrimaryKey = true } @@ -527,7 +450,7 @@ func (a *threeStarIndexAdvisor) extractColumnInSelect() error { // 2. 遍历列的类型 // 把不适合作为索引的列添加到columnShouldNotAdd中 for _, columnDefine := range a.drivingTableCreateStmt.Cols { - if _, exist := a.possibleColumns[columnDefine.Name.Name.L]; !exist { + if !a.possibleColumns.has(&ast.ColumnNameExpr{Name: columnDefine.Name}) { continue } if columnDefine.Tp.Tp == mysql.TypeBlob { @@ -550,13 +473,10 @@ func (a *threeStarIndexAdvisor) Enter(in ast.Node) (out ast.Node, skipChildren b if !a.isColumnInDrivingTable(col) { return in, false } - a.drivingTableColumn.equalColumnInWhere = append( - a.drivingTableColumn.equalColumnInWhere, - columnWithSelectivity{ - columnName: col, - }, - ) + a.drivingTableColumn.equalColumnInWhere.add(col) } + case opcode.LogicOr: + a.usingOr = true case opcode.GE, opcode.GT, opcode.LE, opcode.LT, opcode.NE: if _, ok := currentNode.R.(*parser_driver.ValueExpr); !ok { return in, false @@ -565,12 +485,7 @@ func (a *threeStarIndexAdvisor) Enter(in ast.Node) (out ast.Node, skipChildren b if !a.isColumnInDrivingTable(col) { return in, false } - a.drivingTableColumn.unequalColumnInWhere = append( - a.drivingTableColumn.unequalColumnInWhere, - columnWithSelectivity{ - columnName: col, - }, - ) + a.drivingTableColumn.unequalColumnInWhere.add(col) } } } @@ -581,31 +496,162 @@ func (a *threeStarIndexAdvisor) Leave(in ast.Node) (out ast.Node, ok bool) { return in, true } -func (a threeStarIndexAdvisor) indexColumns() []string { - indexedColumn := make([]string, 0, len(a.adviceColumns)) - for _, column := range a.adviceColumns { - indexedColumn = append(indexedColumn, column.columnName.Name.Name.L) +func (a *threeStarIndexAdvisor) canGiveAdvice() bool { + // 若没有备选的列,则无法给出三星索引建议 + if a.possibleColumns.len() == 0 { + return false } - return indexedColumn + // 如果使用了OR并且无法给出覆盖索引,基于三星索引建议对表加复合索引,该SQL也不会走索引 + // 这种情况应参考创建多个索引触发索引合并优化 + // 参考文档:https://dev.mysql.com/doc/refman/8.0/en/index-merge-optimization.html + if a.usingOr && !a.canGiveCoverIndex() { + return false + } + return true } -type columnWithSelectivity struct { - columnName *ast.ColumnNameExpr - selectivity float64 +func (a *threeStarIndexAdvisor) giveAdvice() { + // 加入WHERE等值条件中的列 + for _, column := range a.drivingTableColumn.equalColumnInWhere.columnsWithSelectivity { + if a.adviceColumns.len() == a.maxColumns { + break + } + if a.shouldSkipColumn(column) { + continue + } + a.adviceColumns.add(column.columnName) + } + // 添加一个排序列 + if a.canAddOrderColumn() { + for _, column := range a.drivingTableColumn.columnInOrderBy.columnsWithSelectivity { + if a.shouldSkipColumn(column) { + continue + } + if a.adviceColumns.len() < a.maxColumns { + a.adviceColumns.add(column.columnName) + } else if a.adviceColumns.columnsWithSelectivity[a.adviceColumns.len()-1].selectivity < column.selectivity { + // 当建议的列已满,此时如果建议的列的最后一列的区分度小于排序列的区分度,则替换该列为排序列 + a.adviceColumns.replace(column, len(a.adviceColumns.columnMap)-1) + } + break + } + } + // 如果能够形成覆盖索引,则添加SELECT中的剩余列 + if a.canGiveCoverIndex() { + for _, column := range a.drivingTableColumn.columnInFieldList.columnsWithSelectivity { + if len(a.adviceColumns.columnMap) == a.maxColumns { + break + } + if a.shouldSkipColumn(column) { + continue + } + a.adviceColumns.add(column.columnName) + } + } + // 最后添加一列WHERE中的非等值列 + if a.canAddUnequalColumn() { + if a.drivingTableColumn.unequalColumnInWhere.len() > 0 { + a.adviceColumns.add(a.drivingTableColumn.unequalColumnInWhere.columnsWithSelectivity[0].columnName) + } + } } -type columnsWithSelectivity []columnWithSelectivity +func (a *threeStarIndexAdvisor) fillColumnWithSelectivity() error { + tableName, ok := a.drivingTableSource.Source.(*ast.TableName) + if !ok { + return fmt.Errorf("in three star advisor driving tableSource.Source is not ast.TableName") + } + selectivityMap, err := a.sqlContext.GetSelectivityOfColumns(tableName, a.possibleColumns.stringSlice()) + if err != nil { + return err + } + // 填充驱动表中各列的列区分度 + a.drivingTableColumn.equalColumnInWhere.setSelectivity(selectivityMap) + a.drivingTableColumn.columnInFieldList.setSelectivity(selectivityMap) + a.drivingTableColumn.columnInOrderBy.setSelectivity(selectivityMap) + a.drivingTableColumn.unequalColumnInWhere.setSelectivity(selectivityMap) + return nil +} -func (c columnsWithSelectivity) Len() int { - return len(c) +func (a *threeStarIndexAdvisor) sortColumnBySelectivity() { + a.drivingTableColumn.columnInOrderBy.sort() + a.drivingTableColumn.columnInFieldList.sort() + a.drivingTableColumn.equalColumnInWhere.sort() + a.drivingTableColumn.unequalColumnInWhere.sort() } -func (c columnsWithSelectivity) Less(i, j int) bool { - return c[i].selectivity > c[j].selectivity +func (a threeStarIndexAdvisor) isColumnInDrivingTable(column *ast.ColumnNameExpr) bool { + if column.Name.Table.L == "" { + // 没有表名,说明只有一张表 + return true + } + return column.Name.Table.L == util.GetTableNameFromTableSource(a.drivingTableSource) } -func (c columnsWithSelectivity) Swap(i, j int) { - c[i], c[j] = c[j], c[i] +func (a threeStarIndexAdvisor) shouldSkipColumn(column columnWithSelectivity) bool { + if !a.possibleColumns.has(column.columnName) { + // 跳过非备选列 + return true + } + if a.adviceColumns.has(column.columnName) { + // 跳过已有列 + return true + } + if a.columnLastAdd.has(column.columnName) { + // 跳过最后添加的列 + return true + } + if a.columnShouldNotAdd.has(column.columnName) { + // 跳过不建议添加的列 + return true + } + return false +} + +func (a threeStarIndexAdvisor) canAddOrderColumn() bool { + originNode, ok := a.originNode.(*ast.SelectStmt) + if !ok { + return false + } + if originNode.OrderBy == nil { + return false + } + if len(originNode.OrderBy.Items) == 0 { + return false + } + // 如果有多个不同方向的排序,则不将排序列放到索引中 + var firstOrder bool = originNode.OrderBy.Items[0].Desc + for _, col := range originNode.OrderBy.Items { + if col.Desc != firstOrder { + return false + } + } + // 如果排序列已在索引建议中则不添加 + for _, column := range a.drivingTableColumn.columnInOrderBy.columnsWithSelectivity { + if a.columnLastAdd.has(column.columnName) { + continue + } + if a.adviceColumns.has(column.columnName) { + return false + } + } + return true +} + +func (a threeStarIndexAdvisor) canAddUnequalColumn() bool { + return a.adviceColumns.len() < a.maxColumns +} + +func (a threeStarIndexAdvisor) canGiveCoverIndex() bool { + // 非等值列大于1时,覆盖索引走不到索引的最后一列,不添加覆盖索引 + if a.drivingTableColumn.unequalColumnInWhere.len() > 1 { + return false + } + // 当备选列大于索引列的上限时,覆盖索引不满足该限制,不添加覆盖索引 + if a.possibleColumns.len() > a.maxColumns { + return false + } + return true } /*