diff --git a/autoid_service/BUILD.bazel b/autoid_service/BUILD.bazel index df3d361d412ed..c973afd85c4e7 100644 --- a/autoid_service/BUILD.bazel +++ b/autoid_service/BUILD.bazel @@ -11,6 +11,7 @@ go_library( "//meta", "//metrics", "//owner", + "//parser/model", "//util/logutil", "//util/mathutil", "@com_github_pingcap_errors//:errors", diff --git a/autoid_service/autoid.go b/autoid_service/autoid.go index f2836fc80fe85..fd0feae76f6bf 100644 --- a/autoid_service/autoid.go +++ b/autoid_service/autoid.go @@ -28,6 +28,7 @@ import ( "github.com/pingcap/tidb/meta" "github.com/pingcap/tidb/metrics" "github.com/pingcap/tidb/owner" + "github.com/pingcap/tidb/parser/model" "github.com/pingcap/tidb/util/logutil" "github.com/pingcap/tidb/util/mathutil" clientv3 "go.etcd.io/etcd/client/v3" @@ -76,7 +77,7 @@ func (alloc *autoIDValue) alloc4Unsigned(ctx context.Context, store kv.Storage, ctx = kv.WithInternalSourceType(ctx, kv.InternalTxnMeta) err := kv.RunInNewTxn(ctx, store, true, func(ctx context.Context, txn kv.Transaction) error { - idAcc := meta.NewMeta(txn).GetAutoIDAccessors(dbID, tblID).RowID() + idAcc := meta.NewMeta(txn).GetAutoIDAccessors(dbID, tblID).IncrementID(model.TableInfoVersion5) var err1 error newBase, err1 = idAcc.Get() if err1 != nil { @@ -137,7 +138,7 @@ func (alloc *autoIDValue) alloc4Signed(ctx context.Context, ctx = kv.WithInternalSourceType(ctx, kv.InternalTxnMeta) err := kv.RunInNewTxn(ctx, store, true, func(ctx context.Context, txn kv.Transaction) error { - idAcc := meta.NewMeta(txn).GetAutoIDAccessors(dbID, tblID).RowID() + idAcc := meta.NewMeta(txn).GetAutoIDAccessors(dbID, tblID).IncrementID(model.TableInfoVersion5) var err1 error newBase, err1 = idAcc.Get() if err1 != nil { @@ -188,7 +189,7 @@ func (alloc *autoIDValue) rebase4Unsigned(ctx context.Context, startTime := time.Now() ctx = kv.WithInternalSourceType(ctx, kv.InternalTxnMeta) err := kv.RunInNewTxn(ctx, store, true, func(ctx context.Context, txn kv.Transaction) error { - idAcc := meta.NewMeta(txn).GetAutoIDAccessors(dbID, tblID).RowID() + idAcc := meta.NewMeta(txn).GetAutoIDAccessors(dbID, tblID).IncrementID(model.TableInfoVersion5) currentEnd, err1 := idAcc.Get() if err1 != nil { return err1 @@ -221,7 +222,7 @@ func (alloc *autoIDValue) rebase4Signed(ctx context.Context, store kv.Storage, d var newBase, newEnd int64 ctx = kv.WithInternalSourceType(ctx, kv.InternalTxnMeta) err := kv.RunInNewTxn(ctx, store, true, func(ctx context.Context, txn kv.Transaction) error { - idAcc := meta.NewMeta(txn).GetAutoIDAccessors(dbID, tblID).RowID() + idAcc := meta.NewMeta(txn).GetAutoIDAccessors(dbID, tblID).IncrementID(model.TableInfoVersion5) currentEnd, err1 := idAcc.Get() if err1 != nil { return err1 @@ -451,7 +452,7 @@ func (s *Service) allocAutoID(ctx context.Context, req *autoid.AutoIDRequest) (* func (alloc *autoIDValue) forceRebase(ctx context.Context, store kv.Storage, dbID, tblID, requiredBase int64, isUnsigned bool) error { ctx = kv.WithInternalSourceType(ctx, kv.InternalTxnMeta) err := kv.RunInNewTxn(ctx, store, true, func(ctx context.Context, txn kv.Transaction) error { - idAcc := meta.NewMeta(txn).GetAutoIDAccessors(dbID, tblID).RowID() + idAcc := meta.NewMeta(txn).GetAutoIDAccessors(dbID, tblID).IncrementID(model.TableInfoVersion5) currentEnd, err1 := idAcc.Get() if err1 != nil { return err1 diff --git a/br/pkg/errors/errors.go b/br/pkg/errors/errors.go index 07e9fb6317cb9..2b7d76e28d795 100644 --- a/br/pkg/errors/errors.go +++ b/br/pkg/errors/errors.go @@ -83,8 +83,9 @@ var ( ErrStorageInvalidPermission = errors.Normalize("external storage permission", errors.RFCCodeText("BR:ExternalStorage:ErrStorageInvalidPermission")) // Snapshot restore - ErrRestoreTotalKVMismatch = errors.Normalize("restore total tikvs mismatch", errors.RFCCodeText("BR:EBS:ErrRestoreTotalKVMismatch")) - ErrRestoreInvalidPeer = errors.Normalize("restore met a invalid peer", errors.RFCCodeText("BR:EBS:ErrRestoreInvalidPeer")) + ErrRestoreTotalKVMismatch = errors.Normalize("restore total tikvs mismatch", errors.RFCCodeText("BR:EBS:ErrRestoreTotalKVMismatch")) + ErrRestoreInvalidPeer = errors.Normalize("restore met a invalid peer", errors.RFCCodeText("BR:EBS:ErrRestoreInvalidPeer")) + ErrRestoreRegionWithoutPeer = errors.Normalize("restore met a region without any peer", errors.RFCCodeText("BR:EBS:ErrRestoreRegionWithoutPeer")) // Errors reported from TiKV. ErrKVStorage = errors.Normalize("tikv storage occur I/O error", errors.RFCCodeText("BR:KV:ErrKVStorage")) diff --git a/br/pkg/lightning/backend/kv/allocator.go b/br/pkg/lightning/backend/kv/allocator.go index 02f46ea8c7e36..14703e1143a45 100644 --- a/br/pkg/lightning/backend/kv/allocator.go +++ b/br/pkg/lightning/backend/kv/allocator.go @@ -34,6 +34,7 @@ type panickingAllocator struct { func NewPanickingAllocators(base int64) autoid.Allocators { sharedBase := &base return autoid.NewAllocators( + false, &panickingAllocator{base: sharedBase, ty: autoid.RowIDAllocType}, &panickingAllocator{base: sharedBase, ty: autoid.AutoIncrementType}, &panickingAllocator{base: sharedBase, ty: autoid.AutoRandomType}, diff --git a/br/pkg/restore/data.go b/br/pkg/restore/data.go index f7efce83362f5..7432c3d9af0ce 100644 --- a/br/pkg/restore/data.go +++ b/br/pkg/restore/data.go @@ -372,6 +372,7 @@ type RecoverRegion struct { // 2. build a leader list for all region during the tikv startup // 3. get max allocate id func (recovery *Recovery) MakeRecoveryPlan() error { + storeBalanceScore := make(map[uint64]int, len(recovery.allStores)) // Group region peer info by region id. find the max allocateId // region [id] [peer[0-n]] var regions = make(map[uint64][]*RecoverRegion, 0) @@ -410,16 +411,20 @@ func (recovery *Recovery) MakeRecoveryPlan() error { } } else { // Generate normal commands. - log.Debug("detected valid peer", zap.Uint64("region id", regionId)) - for i, peer := range peers { - log.Debug("make plan", zap.Uint64("store id", peer.StoreId), zap.Uint64("region id", peer.RegionId)) - plan := &recovpb.RecoverRegionRequest{RegionId: peer.RegionId, AsLeader: i == 0} - // sorted by log term -> last index -> commit index in a region - if plan.AsLeader { - log.Debug("as leader peer", zap.Uint64("store id", peer.StoreId), zap.Uint64("region id", peer.RegionId)) - recovery.RecoveryPlan[peer.StoreId] = append(recovery.RecoveryPlan[peer.StoreId], plan) - } + log.Debug("detected valid region", zap.Uint64("region id", regionId)) + // calc the leader candidates + leaderCandidates, err := LeaderCandidates(peers) + if err != nil { + log.Warn("region without peer", zap.Uint64("region id", regionId)) + return errors.Trace(err) } + + // select the leader base on tikv storeBalanceScore + leader := SelectRegionLeader(storeBalanceScore, leaderCandidates) + log.Debug("as leader peer", zap.Uint64("store id", leader.StoreId), zap.Uint64("region id", leader.RegionId)) + plan := &recovpb.RecoverRegionRequest{RegionId: leader.RegionId, AsLeader: true} + recovery.RecoveryPlan[leader.StoreId] = append(recovery.RecoveryPlan[leader.StoreId], plan) + storeBalanceScore[leader.StoreId] += 1 } } return nil diff --git a/br/pkg/restore/util.go b/br/pkg/restore/util.go index 259d3fa28d888..73a4411c445c1 100644 --- a/br/pkg/restore/util.go +++ b/br/pkg/restore/util.go @@ -750,3 +750,43 @@ func CheckConsistencyAndValidPeer(regionInfos []*RecoverRegionInfo) (map[uint64] } return validPeers, nil } + +// in cloud, since iops and bandwidth limitation, write operator in raft is slow, so raft state (logterm, lastlog, commitlog...) are the same among the peers +// LeaderCandidates select all peers can be select as a leader during the restore +func LeaderCandidates(peers []*RecoverRegion) ([]*RecoverRegion, error) { + if peers == nil { + return nil, errors.Annotatef(berrors.ErrRestoreRegionWithoutPeer, + "invalid region range") + } + candidates := make([]*RecoverRegion, 0, len(peers)) + // by default, the peers[0] to be assign as a leader, since peers already sorted by leader selection rule + leader := peers[0] + candidates = append(candidates, leader) + for _, peer := range peers[1:] { + // qualificated candidate is leader.logterm = candidate.logterm && leader.lastindex = candidate.lastindex && && leader.commitindex = candidate.commitindex + if peer.LastLogTerm == leader.LastLogTerm && peer.LastIndex == leader.LastIndex && peer.CommitIndex == leader.CommitIndex { + log.Debug("leader candidate", zap.Uint64("store id", peer.StoreId), zap.Uint64("region id", peer.RegionId), zap.Uint64("peer id", peer.PeerId)) + candidates = append(candidates, peer) + } + } + return candidates, nil +} + +// for region A, has candidate leader x, y, z +// peer x on store 1 with storeBalanceScore 3 +// peer y on store 3 with storeBalanceScore 2 +// peer z on store 4 with storeBalanceScore 1 +// result: peer z will be select as leader on store 4 +func SelectRegionLeader(storeBalanceScore map[uint64]int, peers []*RecoverRegion) *RecoverRegion { + // by default, the peers[0] to be assign as a leader + leader := peers[0] + minLeaderStore := storeBalanceScore[leader.StoreId] + for _, peer := range peers[1:] { + log.Debug("leader candidate", zap.Int("score", storeBalanceScore[peer.StoreId]), zap.Int("min-score", minLeaderStore), zap.Uint64("store id", peer.StoreId), zap.Uint64("region id", peer.RegionId), zap.Uint64("peer id", peer.PeerId)) + if storeBalanceScore[peer.StoreId] < minLeaderStore { + minLeaderStore = storeBalanceScore[peer.StoreId] + leader = peer + } + } + return leader +} diff --git a/br/pkg/restore/util_test.go b/br/pkg/restore/util_test.go index 44620e9cb4e5c..482818a1ad958 100644 --- a/br/pkg/restore/util_test.go +++ b/br/pkg/restore/util_test.go @@ -460,3 +460,52 @@ func TestCheckConsistencyAndValidPeer(t *testing.T) { require.Error(t, err) require.Regexp(t, ".*invalid restore range.*", err.Error()) } + +func TestLeaderCandidates(t *testing.T) { + //key space is continuous + validPeer1 := newPeerMeta(9, 11, 2, []byte(""), []byte("bb"), 2, 1, 0, 0, false) + validPeer2 := newPeerMeta(19, 22, 3, []byte("bb"), []byte("cc"), 2, 1, 0, 1, false) + validPeer3 := newPeerMeta(29, 30, 1, []byte("cc"), []byte(""), 2, 1, 0, 2, false) + + peers := []*restore.RecoverRegion{ + validPeer1, + validPeer2, + validPeer3, + } + + candidates, err := restore.LeaderCandidates(peers) + require.NoError(t, err) + require.Equal(t, 3, len(candidates)) +} + +func TestSelectRegionLeader(t *testing.T) { + validPeer1 := newPeerMeta(9, 11, 2, []byte(""), []byte("bb"), 2, 1, 0, 0, false) + validPeer2 := newPeerMeta(19, 22, 3, []byte("bb"), []byte("cc"), 2, 1, 0, 1, false) + validPeer3 := newPeerMeta(29, 30, 1, []byte("cc"), []byte(""), 2, 1, 0, 2, false) + + peers := []*restore.RecoverRegion{ + validPeer1, + validPeer2, + validPeer3, + } + // init store banlance score all is 0 + storeBalanceScore := make(map[uint64]int, len(peers)) + leader := restore.SelectRegionLeader(storeBalanceScore, peers) + require.Equal(t, validPeer1, leader) + + // change store banlance store + storeBalanceScore[2] = 3 + storeBalanceScore[3] = 2 + storeBalanceScore[1] = 1 + leader = restore.SelectRegionLeader(storeBalanceScore, peers) + require.Equal(t, validPeer3, leader) + + // one peer + peer := []*restore.RecoverRegion{ + validPeer3, + } + // init store banlance score all is 0 + storeScore := make(map[uint64]int, len(peer)) + leader = restore.SelectRegionLeader(storeScore, peer) + require.Equal(t, validPeer3, leader) +} diff --git a/ddl/column.go b/ddl/column.go index 96ab745377a92..9f5174737915a 100644 --- a/ddl/column.go +++ b/ddl/column.go @@ -1543,7 +1543,7 @@ func checkAndApplyAutoRandomBits(d *ddlCtx, m *meta.Meta, dbInfo *model.DBInfo, return nil } idAcc := m.GetAutoIDAccessors(dbInfo.ID, tblInfo.ID) - err := checkNewAutoRandomBits(idAcc, oldCol, newCol, newAutoRandBits, tblInfo.AutoRandomRangeBits, tblInfo.Version) + err := checkNewAutoRandomBits(idAcc, oldCol, newCol, newAutoRandBits, tblInfo.AutoRandomRangeBits, tblInfo.SepAutoInc()) if err != nil { return err } @@ -1552,13 +1552,17 @@ func checkAndApplyAutoRandomBits(d *ddlCtx, m *meta.Meta, dbInfo *model.DBInfo, // checkNewAutoRandomBits checks whether the new auto_random bits number can cause overflow. func checkNewAutoRandomBits(idAccessors meta.AutoIDAccessors, oldCol *model.ColumnInfo, - newCol *model.ColumnInfo, newShardBits, newRangeBits uint64, tblVer uint16) error { + newCol *model.ColumnInfo, newShardBits, newRangeBits uint64, sepAutoInc bool) error { shardFmt := autoid.NewShardIDFormat(&newCol.FieldType, newShardBits, newRangeBits) idAcc := idAccessors.RandomID() convertedFromAutoInc := mysql.HasAutoIncrementFlag(oldCol.GetFlag()) if convertedFromAutoInc { - idAcc = idAccessors.IncrementID(tblVer) + if sepAutoInc { + idAcc = idAccessors.IncrementID(model.TableInfoVersion5) + } else { + idAcc = idAccessors.RowID() + } } // Generate a new auto ID first to prevent concurrent update in DML. _, err := idAcc.Inc(1) diff --git a/ddl/db_integration_test.go b/ddl/db_integration_test.go index b25aa87f2fce8..6d2e5cf39c468 100644 --- a/ddl/db_integration_test.go +++ b/ddl/db_integration_test.go @@ -2926,94 +2926,84 @@ func TestAutoIncrementForce(t *testing.T) { return gid } - for _, str := range []string{"", " AUTO_ID_CACHE 1"} { - // Rebase _tidb_row_id. - tk.MustExec("create table t (a int)" + str) - tk.MustExec("alter table t force auto_increment = 2;") - tk.MustExec("insert into t values (1),(2);") - tk.MustQuery("select a, _tidb_rowid from t;").Check(testkit.Rows("1 2", "2 3")) - // Cannot set next global ID to 0. - tk.MustGetErrCode("alter table t force auto_increment = 0;", errno.ErrAutoincReadFailed) - tk.MustExec("alter table t force auto_increment = 1;") - require.Equal(t, uint64(1), getNextGlobalID()) - // inserting new rows can overwrite the existing data. - tk.MustExec("insert into t values (3);") - require.Equal(t, "[kv:1062]Duplicate entry '2' for key 't.PRIMARY'", tk.ExecToErr("insert into t values (3);").Error()) - tk.MustQuery("select a, _tidb_rowid from t;").Check(testkit.Rows("3 1", "1 2", "2 3")) - tk.MustExec("drop table if exists t;") - } + // Rebase _tidb_row_id. + tk.MustExec("create table t (a int)") + tk.MustExec("alter table t force auto_increment = 2;") + tk.MustExec("insert into t values (1),(2);") + tk.MustQuery("select a, _tidb_rowid from t;").Check(testkit.Rows("1 2", "2 3")) + // Cannot set next global ID to 0. + tk.MustGetErrCode("alter table t force auto_increment = 0;", errno.ErrAutoincReadFailed) + tk.MustExec("alter table t force auto_increment = 1;") + require.Equal(t, uint64(1), getNextGlobalID()) + // inserting new rows can overwrite the existing data. + tk.MustExec("insert into t values (3);") + require.Equal(t, "[kv:1062]Duplicate entry '2' for key 't.PRIMARY'", tk.ExecToErr("insert into t values (3);").Error()) + tk.MustQuery("select a, _tidb_rowid from t;").Check(testkit.Rows("3 1", "1 2", "2 3")) + tk.MustExec("drop table if exists t;") - for _, str := range []string{"", " AUTO_ID_CACHE 1"} { - // Rebase auto_increment. - tk.MustExec("create table t (a int primary key auto_increment, b int)" + str) - tk.MustExec("insert into t values (1, 1);") - tk.MustExec("insert into t values (100000000, 1);") - tk.MustExec("delete from t where a = 100000000;") - require.Greater(t, getNextGlobalID(), uint64(100000000)) - // Cannot set next global ID to 0. - tk.MustGetErrCode("alter table t /*T![force_inc] force */ auto_increment = 0;", errno.ErrAutoincReadFailed) - tk.MustExec("alter table t /*T![force_inc] force */ auto_increment = 2;") - require.Equal(t, uint64(2), getNextGlobalID()) - tk.MustExec("insert into t(b) values (2);") - tk.MustQuery("select a, b from t;").Check(testkit.Rows("1 1", "2 2")) - tk.MustExec("drop table if exists t;") - } + // Rebase auto_increment. + tk.MustExec("create table t (a int primary key auto_increment, b int)") + tk.MustExec("insert into t values (1, 1);") + tk.MustExec("insert into t values (100000000, 1);") + tk.MustExec("delete from t where a = 100000000;") + require.Greater(t, getNextGlobalID(), uint64(100000000)) + // Cannot set next global ID to 0. + tk.MustGetErrCode("alter table t /*T![force_inc] force */ auto_increment = 0;", errno.ErrAutoincReadFailed) + tk.MustExec("alter table t /*T![force_inc] force */ auto_increment = 2;") + require.Equal(t, uint64(2), getNextGlobalID()) + tk.MustExec("insert into t(b) values (2);") + tk.MustQuery("select a, b from t;").Check(testkit.Rows("1 1", "2 2")) + tk.MustExec("drop table if exists t;") - for _, str := range []string{"", " AUTO_ID_CACHE 1"} { - // Rebase auto_random. - tk.MustExec("create table t (a bigint primary key auto_random(5))" + str) - tk.MustExec("insert into t values ();") - tk.MustExec("set @@allow_auto_random_explicit_insert = true") - tk.MustExec("insert into t values (100000000);") - tk.MustExec("delete from t where a = 100000000;") - require.Greater(t, getNextGlobalID(), uint64(100000000)) - // Cannot set next global ID to 0. - tk.MustGetErrCode("alter table t force auto_random_base = 0;", errno.ErrAutoincReadFailed) - tk.MustExec("alter table t force auto_random_base = 2;") - require.Equal(t, uint64(2), getNextGlobalID()) - tk.MustExec("insert into t values ();") - tk.MustQuery("select (a & 3) from t order by 1;").Check(testkit.Rows("1", "2")) - tk.MustExec("drop table if exists t;") - } + // Rebase auto_random. + tk.MustExec("create table t (a bigint primary key auto_random(5))") + tk.MustExec("insert into t values ();") + tk.MustExec("set @@allow_auto_random_explicit_insert = true") + tk.MustExec("insert into t values (100000000);") + tk.MustExec("delete from t where a = 100000000;") + require.Greater(t, getNextGlobalID(), uint64(100000000)) + // Cannot set next global ID to 0. + tk.MustGetErrCode("alter table t force auto_random_base = 0;", errno.ErrAutoincReadFailed) + tk.MustExec("alter table t force auto_random_base = 2;") + require.Equal(t, uint64(2), getNextGlobalID()) + tk.MustExec("insert into t values ();") + tk.MustQuery("select (a & 3) from t order by 1;").Check(testkit.Rows("1", "2")) + tk.MustExec("drop table if exists t;") - for _, str := range []string{"", " AUTO_ID_CACHE 1"} { - // Change next global ID. - tk.MustExec("create table t (a bigint primary key auto_increment)" + str) - tk.MustExec("insert into t values (1);") - bases := []uint64{1, 65535, 10, math.MaxUint64, math.MaxInt64 + 1, 1, math.MaxUint64, math.MaxInt64, 2} - lastBase := fmt.Sprintf("%d", bases[len(bases)-1]) - for _, b := range bases { - fmt.Println("execute alter table force increment to ==", b) - tk.MustExec(fmt.Sprintf("alter table t force auto_increment = %d;", b)) - require.Equal(t, b, getNextGlobalID()) - } + // Change next global ID. + tk.MustExec("create table t (a bigint primary key auto_increment)") + tk.MustExec("insert into t values (1);") + bases := []uint64{1, 65535, 10, math.MaxUint64, math.MaxInt64 + 1, 1, math.MaxUint64, math.MaxInt64, 2} + lastBase := fmt.Sprintf("%d", bases[len(bases)-1]) + for _, b := range bases { + fmt.Println("execute alter table force increment to ==", b) + tk.MustExec(fmt.Sprintf("alter table t force auto_increment = %d;", b)) + require.Equal(t, b, getNextGlobalID()) + } + tk.MustExec("insert into t values ();") + tk.MustQuery("select a from t;").Check(testkit.Rows("1", lastBase)) + // Force alter unsigned int auto_increment column. + tk.MustExec("drop table if exists t;") + tk.MustExec("create table t (a bigint unsigned primary key auto_increment)") + for _, b := range bases { + tk.MustExec(fmt.Sprintf("alter table t force auto_increment = %d;", b)) + require.Equal(t, b, getNextGlobalID()) tk.MustExec("insert into t values ();") - tk.MustQuery("select a from t;").Check(testkit.Rows("1", lastBase)) - // Force alter unsigned int auto_increment column. - tk.MustExec("drop table if exists t;") - tk.MustExec("create table t (a bigint unsigned primary key auto_increment)" + str) - for _, b := range bases { - tk.MustExec(fmt.Sprintf("alter table t force auto_increment = %d;", b)) - require.Equal(t, b, getNextGlobalID()) - tk.MustExec("insert into t values ();") - tk.MustQuery("select a from t;").Check(testkit.Rows(fmt.Sprintf("%d", b))) - tk.MustExec("delete from t;") - } - tk.MustExec("drop table if exists t;") + tk.MustQuery("select a from t;").Check(testkit.Rows(fmt.Sprintf("%d", b))) + tk.MustExec("delete from t;") } + tk.MustExec("drop table if exists t;") - for _, str := range []string{"", " AUTO_ID_CACHE 1"} { - // Force alter with @@auto_increment_increment and @@auto_increment_offset. - tk.MustExec("create table t(a int key auto_increment)" + str) - tk.MustExec("set @@auto_increment_offset=2;") - tk.MustExec("set @@auto_increment_increment = 11;") - tk.MustExec("insert into t values (500);") - tk.MustExec("alter table t force auto_increment=100;") - tk.MustExec("insert into t values (), ();") - tk.MustQuery("select * from t;").Check(testkit.Rows("101", "112", "500")) - tk.MustQuery("select * from t order by a;").Check(testkit.Rows("101", "112", "500")) - tk.MustExec("drop table if exists t;") - } + // Force alter with @@auto_increment_increment and @@auto_increment_offset. + tk.MustExec("create table t(a int key auto_increment)") + tk.MustExec("set @@auto_increment_offset=2;") + tk.MustExec("set @@auto_increment_increment = 11;") + tk.MustExec("insert into t values (500);") + tk.MustExec("alter table t force auto_increment=100;") + tk.MustExec("insert into t values (), ();") + tk.MustQuery("select * from t;").Check(testkit.Rows("101", "112", "500")) + tk.MustQuery("select * from t order by a;").Check(testkit.Rows("101", "112", "500")) + tk.MustExec("drop table if exists t;") // Check for warning in case we can't set the auto_increment to the desired value tk.MustExec("create table t(a int primary key auto_increment)") @@ -3033,6 +3023,147 @@ func TestAutoIncrementForce(t *testing.T) { tk.MustExec("drop table t") } +func TestAutoIncrementForceAutoIDCache(t *testing.T) { + store := testkit.CreateMockStore(t) + tk := testkit.NewTestKit(t, store) + tk.MustExec("drop database if exists auto_inc_force;") + tk.MustExec("create database auto_inc_force;") + tk.MustExec("use auto_inc_force;") + getNextGlobalID := func() uint64 { + gidStr := tk.MustQuery("show table t next_row_id").Rows()[0][3] + gid, err := strconv.ParseUint(gidStr.(string), 10, 64) + require.NoError(t, err) + return gid + } + + // Rebase _tidb_row_id. + tk.MustExec("create table t (a int) AUTO_ID_CACHE 1") + tk.MustExec("alter table t force auto_increment = 2;") + tk.MustExec("insert into t values (1),(2);") + tk.MustQuery("select a, _tidb_rowid from t;").Check(testkit.Rows("1 1", "2 2")) + // Cannot set next global ID to 0. + tk.MustExec("alter table t force auto_increment = 0;") + tk.MustExec("alter table t force auto_increment = 1;") + require.Equal(t, uint64(3), getNextGlobalID()) + // inserting new rows can overwrite the existing data. + tk.MustExec("insert into t values (3);") + tk.MustExec("insert into t values (3);") + tk.MustQuery("select a, _tidb_rowid from t;").Check(testkit.Rows("1 1", "2 2", "3 3", "3 4")) + tk.MustExec("drop table if exists t;") + + // When AUTO_ID_CACHE is 1, row id and auto increment id use separate allocator, so the behaviour differs. + // "Alter table t force auto_increment" has no effect on row id. + tk.MustExec("create table t (a int) AUTO_ID_CACHE 1") + tk.MustExec("alter table t force auto_increment = 2;") + tk.MustExec("insert into t values (1),(2);") + tk.MustQuery("select a, _tidb_rowid from t;").Check(testkit.Rows("1 1", "2 2")) + // Cannot set next global ID to 0. + tk.MustExec("alter table t force auto_increment = 0;") + tk.MustExec("alter table t force auto_increment = 1;") + require.Equal(t, uint64(3), getNextGlobalID()) + // inserting new rows can overwrite the existing data. + tk.MustExec("insert into t values (3);") + tk.MustExec("insert into t values (3);") + tk.MustQuery("select a, _tidb_rowid from t;").Check(testkit.Rows("1 1", "2 2", "3 3", "3 4")) + tk.MustExec("drop table if exists t;") + + // Rebase auto_increment. + tk.MustExec("create table t (a int primary key auto_increment, b int) AUTO_ID_CACHE 1") + tk.MustExec("insert into t values (1, 1);") + tk.MustExec("insert into t values (100000000, 1);") + tk.MustExec("delete from t where a = 100000000;") + tk.MustQuery("show table t next_row_id").Check(testkit.Rows( + "auto_inc_force t a 1 _TIDB_ROWID", + "auto_inc_force t a 100000001 AUTO_INCREMENT", + )) + // Cannot set next global ID to 0. + tk.MustGetErrCode("alter table t /*T![force_inc] force */ auto_increment = 0;", errno.ErrAutoincReadFailed) + tk.MustExec("alter table t /*T![force_inc] force */ auto_increment = 2;") + tk.MustQuery("show table t next_row_id").Check(testkit.Rows( + "auto_inc_force t a 1 _TIDB_ROWID", + "auto_inc_force t a 2 AUTO_INCREMENT", + )) + + tk.MustExec("insert into t(b) values (2);") + tk.MustQuery("select a, b from t;").Check(testkit.Rows("1 1", "2 2")) + tk.MustExec("drop table if exists t;") + + // Rebase auto_random. + tk.MustExec("create table t (a bigint primary key auto_random(5)) AUTO_ID_CACHE 1") + tk.MustExec("insert into t values ();") + tk.MustExec("set @@allow_auto_random_explicit_insert = true") + tk.MustExec("insert into t values (100000000);") + tk.MustExec("delete from t where a = 100000000;") + require.Greater(t, getNextGlobalID(), uint64(100000000)) + // Cannot set next global ID to 0. + tk.MustGetErrCode("alter table t force auto_random_base = 0;", errno.ErrAutoincReadFailed) + tk.MustExec("alter table t force auto_random_base = 2;") + require.Equal(t, uint64(2), getNextGlobalID()) + tk.MustExec("insert into t values ();") + tk.MustQuery("select (a & 3) from t order by 1;").Check(testkit.Rows("1", "2")) + tk.MustExec("drop table if exists t;") + + // Change next global ID. + tk.MustExec("create table t (a bigint primary key auto_increment) AUTO_ID_CACHE 1") + tk.MustExec("insert into t values (1);") + bases := []uint64{1, 65535, 10, math.MaxUint64, math.MaxInt64 + 1, 1, math.MaxUint64, math.MaxInt64, 2} + lastBase := fmt.Sprintf("%d", bases[len(bases)-1]) + for _, b := range bases { + fmt.Println("execute alter table force increment to ==", b) + tk.MustExec(fmt.Sprintf("alter table t force auto_increment = %d;", b)) + tk.MustQuery("show table t next_row_id").Check(testkit.Rows( + "auto_inc_force t a 1 _TIDB_ROWID", + fmt.Sprintf("auto_inc_force t a %d AUTO_INCREMENT", b), + )) + } + tk.MustExec("insert into t values ();") + tk.MustQuery("select a from t;").Check(testkit.Rows("1", lastBase)) + // Force alter unsigned int auto_increment column. + tk.MustExec("drop table if exists t;") + tk.MustExec("create table t (a bigint unsigned primary key auto_increment) AUTO_ID_CACHE 1") + for _, b := range bases { + tk.MustExec(fmt.Sprintf("alter table t force auto_increment = %d;", b)) + tk.MustQuery("show table t next_row_id").Check(testkit.Rows( + "auto_inc_force t a 1 _TIDB_ROWID", + fmt.Sprintf("auto_inc_force t a %d AUTO_INCREMENT", b), + )) + tk.MustExec("insert into t values ();") + tk.MustQuery("select a from t;").Check(testkit.Rows(fmt.Sprintf("%d", b))) + tk.MustExec("delete from t;") + } + tk.MustExec("drop table if exists t;") + + // Force alter with @@auto_increment_increment and @@auto_increment_offset. + tk.MustExec("create table t(a int key auto_increment) AUTO_ID_CACHE 1") + tk.MustExec("set @@auto_increment_offset=2;") + tk.MustExec("set @@auto_increment_increment = 11;") + tk.MustExec("insert into t values (500);") + tk.MustExec("alter table t force auto_increment=100;") + tk.MustExec("insert into t values (), ();") + tk.MustQuery("select * from t;").Check(testkit.Rows("101", "112", "500")) + tk.MustQuery("select * from t order by a;").Check(testkit.Rows("101", "112", "500")) + tk.MustExec("drop table if exists t;") + + // Check for warning in case we can't set the auto_increment to the desired value + tk.MustExec("create table t(a int primary key auto_increment) AUTO_ID_CACHE 1") + tk.MustExec("insert into t values (200)") + tk.MustQuery("show create table t").Check(testkit.Rows( + "t CREATE TABLE `t` (\n" + + " `a` int(11) NOT NULL AUTO_INCREMENT,\n" + + " PRIMARY KEY (`a`) /*T![clustered_index] CLUSTERED */\n" + + ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin /*T![auto_id_cache] AUTO_ID_CACHE=1 */")) + tk.MustExec("alter table t auto_increment=100;") + tk.MustQuery("show warnings").Check(testkit.Rows("Warning 1105 Can't reset AUTO_INCREMENT to 100 without FORCE option, using 201 instead")) + tk.MustExec("insert into t values ()") + tk.MustQuery("select * from t").Check(testkit.Rows("200", "211")) + tk.MustQuery("show create table t").Check(testkit.Rows( + "t CREATE TABLE `t` (\n" + + " `a` int(11) NOT NULL AUTO_INCREMENT,\n" + + " PRIMARY KEY (`a`) /*T![clustered_index] CLUSTERED */\n" + + ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin /*T![auto_id_cache] AUTO_ID_CACHE=1 */")) + tk.MustExec("drop table t") +} + func TestIssue20490(t *testing.T) { store := testkit.CreateMockStore(t, mockstore.WithDDLChecker()) diff --git a/ddl/db_test.go b/ddl/db_test.go index ce2ea307e97af..5990df4634a68 100644 --- a/ddl/db_test.go +++ b/ddl/db_test.go @@ -898,11 +898,11 @@ func TestAutoIncrementIDOnTemporaryTable(t *testing.T) { tk.MustExec("drop table if exists global_temp_auto_id") tk.MustExec("create global temporary table global_temp_auto_id(id int primary key auto_increment) on commit delete rows") tk.MustExec("begin") - tk.MustQuery("show table global_temp_auto_id next_row_id").Check(testkit.Rows("test global_temp_auto_id id 1 AUTO_INCREMENT")) + tk.MustQuery("show table global_temp_auto_id next_row_id").Check(testkit.Rows("test global_temp_auto_id id 1 _TIDB_ROWID")) tk.MustExec("insert into global_temp_auto_id value(null)") tk.MustQuery("select @@last_insert_id").Check(testkit.Rows("1")) tk.MustQuery("select id from global_temp_auto_id").Check(testkit.Rows("1")) - tk.MustQuery("show table global_temp_auto_id next_row_id").Check(testkit.Rows("test global_temp_auto_id id 2 AUTO_INCREMENT")) + tk.MustQuery("show table global_temp_auto_id next_row_id").Check(testkit.Rows("test global_temp_auto_id id 2 _TIDB_ROWID")) tk.MustExec("commit") tk.MustExec("drop table global_temp_auto_id") @@ -914,12 +914,12 @@ func TestAutoIncrementIDOnTemporaryTable(t *testing.T) { " `id` int(11) NOT NULL AUTO_INCREMENT,\n" + " PRIMARY KEY (`id`) /*T![clustered_index] CLUSTERED */\n" + ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin AUTO_INCREMENT=100 ON COMMIT DELETE ROWS")) - tk.MustQuery("show table global_temp_auto_id next_row_id").Check(testkit.Rows("test global_temp_auto_id id 100 AUTO_INCREMENT")) + tk.MustQuery("show table global_temp_auto_id next_row_id").Check(testkit.Rows("test global_temp_auto_id id 100 _TIDB_ROWID")) tk.MustExec("begin") tk.MustExec("insert into global_temp_auto_id value(null)") tk.MustQuery("select @@last_insert_id").Check(testkit.Rows("100")) tk.MustQuery("select id from global_temp_auto_id").Check(testkit.Rows("100")) - tk.MustQuery("show table global_temp_auto_id next_row_id").Check(testkit.Rows("test global_temp_auto_id id 101 AUTO_INCREMENT")) + tk.MustQuery("show table global_temp_auto_id next_row_id").Check(testkit.Rows("test global_temp_auto_id id 101 _TIDB_ROWID")) tk.MustExec("commit") } tk.MustExec("drop table global_temp_auto_id") diff --git a/ddl/ddl_api.go b/ddl/ddl_api.go index 505d413fff8c2..1816e0d65891d 100644 --- a/ddl/ddl_api.go +++ b/ddl/ddl_api.go @@ -2152,7 +2152,7 @@ func checkPartitionDefinitionConstraints(ctx sessionctx.Context, tbInfo *model.T // checkTableInfoValid uses to check table info valid. This is used to validate table info. func checkTableInfoValid(tblInfo *model.TableInfo) error { - _, err := tables.TableFromMeta(nil, tblInfo) + _, err := tables.TableFromMeta(autoid.NewAllocators(false), tblInfo) if err != nil { return err } @@ -2493,7 +2493,13 @@ func (d *ddl) createTableWithInfoPost( // Default tableAutoIncID base is 0. // If the first ID is expected to greater than 1, we need to do rebase. newEnd := tbInfo.AutoIncID - 1 - if err = d.handleAutoIncID(tbInfo, schemaID, newEnd, autoid.RowIDAllocType); err != nil { + var allocType autoid.AllocatorType + if tbInfo.SepAutoInc() { + allocType = autoid.AutoIncrementType + } else { + allocType = autoid.RowIDAllocType + } + if err = d.handleAutoIncID(tbInfo, schemaID, newEnd, allocType); err != nil { return errors.Trace(err) } } @@ -3361,7 +3367,7 @@ func (d *ddl) AlterTable(ctx context.Context, sctx sessionctx.Context, stmt *ast } err = d.ShardRowID(sctx, ident, opt.UintValue) case ast.TableOptionAutoIncrement: - err = d.RebaseAutoID(sctx, ident, int64(opt.UintValue), autoid.RowIDAllocType, opt.BoolValue) + err = d.RebaseAutoID(sctx, ident, int64(opt.UintValue), autoid.AutoIncrementType, opt.BoolValue) case ast.TableOptionAutoIdCache: if opt.UintValue > uint64(math.MaxInt64) { // TODO: Refine this error. @@ -3492,6 +3498,10 @@ func (d *ddl) RebaseAutoID(ctx sessionctx.Context, ident ast.Ident, newBase int6 actionType = model.ActionRebaseAutoRandomBase case autoid.RowIDAllocType: actionType = model.ActionRebaseAutoID + case autoid.AutoIncrementType: + actionType = model.ActionRebaseAutoID + default: + panic(fmt.Sprintf("unimplemented rebase autoid type %s", tp)) } if !force { @@ -5203,6 +5213,11 @@ func (d *ddl) AlterTableAutoIDCache(ctx sessionctx.Context, ident ast.Ident, new if err != nil { return errors.Trace(err) } + tbInfo := tb.Meta() + if (newCache == 1 && tbInfo.AutoIdCache != 1) || + (newCache != 1 && tbInfo.AutoIdCache == 1) { + return fmt.Errorf("Can't Alter AUTO_ID_CACHE between 1 and non-1, the underlying implementation is different") + } job := &model.Job{ SchemaID: schema.ID, diff --git a/ddl/ddl_worker.go b/ddl/ddl_worker.go index 1a13feb81e079..850caca29e404 100644 --- a/ddl/ddl_worker.go +++ b/ddl/ddl_worker.go @@ -1232,7 +1232,7 @@ func (w *worker) runDDLJob(d *ddlCtx, t *meta.Meta, job *model.Job) (ver int64, case model.ActionTruncateTable: ver, err = onTruncateTable(d, t, job) case model.ActionRebaseAutoID: - ver, err = onRebaseRowIDType(d, t, job) + ver, err = onRebaseAutoIncrementIDType(d, t, job) case model.ActionRebaseAutoRandomBase: ver, err = onRebaseAutoRandomType(d, t, job) case model.ActionRenameTable: diff --git a/ddl/multi_schema_change_test.go b/ddl/multi_schema_change_test.go index f302737d60c3b..0f8aeca87802c 100644 --- a/ddl/multi_schema_change_test.go +++ b/ddl/multi_schema_change_test.go @@ -1177,7 +1177,7 @@ func TestMultiSchemaChangeUnsupportedType(t *testing.T) { tk.MustExec("use test;") tk.MustExec("create table t (a int, b int);") - tk.MustGetErrMsg("alter table t add column c int, auto_id_cache = 1;", + tk.MustGetErrMsg("alter table t add column c int, auto_id_cache = 10;", "[ddl:8200]Unsupported multi schema change for modify auto id cache") } diff --git a/ddl/partition.go b/ddl/partition.go index a8947d091bfc5..cf4bd7aed962f 100644 --- a/ddl/partition.go +++ b/ddl/partition.go @@ -2077,7 +2077,7 @@ func (w *worker) onExchangeTablePartition(d *ddlCtx, t *meta.Meta, job *model.Jo failpoint.Return(ver, err) } sess := newSession(se) - _, err = sess.execute(context.Background(), "insert into test.pt values (40000000)", "exchange_partition_test") + _, err = sess.execute(context.Background(), "insert ignore into test.pt values (40000000)", "exchange_partition_test") if err != nil { failpoint.Return(ver, err) } diff --git a/ddl/table.go b/ddl/table.go index a6e2d93b5ac7e..9e6fab762d3c5 100644 --- a/ddl/table.go +++ b/ddl/table.go @@ -812,8 +812,8 @@ func onTruncateTable(d *ddlCtx, t *meta.Meta, job *model.Job) (ver int64, _ erro return ver, nil } -func onRebaseRowIDType(d *ddlCtx, t *meta.Meta, job *model.Job) (ver int64, _ error) { - return onRebaseAutoID(d, d.store, t, job, autoid.RowIDAllocType) +func onRebaseAutoIncrementIDType(d *ddlCtx, t *meta.Meta, job *model.Job) (ver int64, _ error) { + return onRebaseAutoID(d, d.store, t, job, autoid.AutoIncrementType) } func onRebaseAutoRandomType(d *ddlCtx, t *meta.Meta, job *model.Job) (ver int64, _ error) { @@ -862,7 +862,7 @@ func onRebaseAutoID(d *ddlCtx, store kv.Storage, t *meta.Meta, job *model.Job, t newBase = newBaseTemp } - if tp == autoid.RowIDAllocType { + if tp == autoid.AutoIncrementType { tblInfo.AutoIncID = newBase } else { tblInfo.AutoRandID = newBase diff --git a/ddl/table_test.go b/ddl/table_test.go index 9641c24eb0f19..e0e1c45e3b0ef 100644 --- a/ddl/table_test.go +++ b/ddl/table_test.go @@ -160,7 +160,7 @@ func testGetTableWithError(store kv.Storage, schemaID, tableID int64) (table.Tab return nil, errors.New("table not found") } alloc := autoid.NewAllocator(store, schemaID, tblInfo.ID, false, autoid.RowIDAllocType) - tbl, err := table.TableFromMeta(autoid.NewAllocators(alloc), tblInfo) + tbl, err := table.TableFromMeta(autoid.NewAllocators(false, alloc), tblInfo) if err != nil { return nil, errors.Trace(err) } diff --git a/distsql/distsql_test.go b/distsql/distsql_test.go index 52aa62ba112fa..bf5593596a18b 100644 --- a/distsql/distsql_test.go +++ b/distsql/distsql_test.go @@ -107,7 +107,8 @@ func TestSelectWithRuntimeStats(t *testing.T) { } func TestSelectResultRuntimeStats(t *testing.T) { - basic := &execdetails.BasicRuntimeStats{} + stmtStats := execdetails.NewRuntimeStatsColl(nil) + basic := stmtStats.GetBasicRuntimeStats(1) basic.Record(time.Second, 20) s1 := &selectResultRuntimeStats{ copRespTime: []time.Duration{time.Second, time.Millisecond}, @@ -120,8 +121,6 @@ func TestSelectResultRuntimeStats(t *testing.T) { } s2 := *s1 - stmtStats := execdetails.NewRuntimeStatsColl(nil) - stmtStats.RegisterStats(1, basic) stmtStats.RegisterStats(1, s1) stmtStats.RegisterStats(1, &s2) stats := stmtStats.GetRootStats(1) @@ -136,7 +135,7 @@ func TestSelectResultRuntimeStats(t *testing.T) { } stmtStats.RegisterStats(2, s1) stats = stmtStats.GetRootStats(2) - expect = "cop_task: {num: 2, max: 1s, min: 1ms, avg: 500.5ms, p95: 1s, max_proc_keys: 200, p95_proc_keys: 200, tot_proc: 1s, tot_wait: 1s, rpc_num: 1, rpc_time: 1s, copr_cache_hit_ratio: 0.00, distsql_concurrency: 15}, backoff{RegionMiss: 1ms}" + expect = "time:0s, loops:0, cop_task: {num: 2, max: 1s, min: 1ms, avg: 500.5ms, p95: 1s, max_proc_keys: 200, p95_proc_keys: 200, tot_proc: 1s, tot_wait: 1s, rpc_num: 1, rpc_time: 1s, copr_cache_hit_ratio: 0.00, distsql_concurrency: 15}, backoff{RegionMiss: 1ms}" require.Equal(t, expect, stats.String()) // Test for idempotence. require.Equal(t, expect, stats.String()) diff --git a/distsql/select_result.go b/distsql/select_result.go index 0e807b360d0ad..6d1f6308e4120 100644 --- a/distsql/select_result.go +++ b/distsql/select_result.go @@ -359,13 +359,11 @@ func (r *selectResult) updateCopRuntimeStats(ctx context.Context, copStats *copr } if r.stats == nil { - id := r.rootPlanID r.stats = &selectResultRuntimeStats{ backoffSleep: make(map[string]time.Duration), rpcStat: tikv.NewRegionRequestRuntimeStats(), distSQLConcurrency: r.distSQLConcurrency, } - r.ctx.GetSessionVars().StmtCtx.RuntimeStatsColl.RegisterStats(id, r.stats) } r.stats.mergeCopRuntimeStats(copStats, respTime) @@ -456,6 +454,9 @@ func (r *selectResult) Close() error { if respSize > 0 { r.memConsume(-respSize) } + if r.stats != nil { + defer r.ctx.GetSessionVars().StmtCtx.RuntimeStatsColl.RegisterStats(r.rootPlanID, r.stats) + } return r.resp.Close() } diff --git a/distsql/select_result_test.go b/distsql/select_result_test.go index c12892083d641..4ec56a286e5ab 100644 --- a/distsql/select_result_test.go +++ b/distsql/select_result_test.go @@ -34,7 +34,7 @@ func TestUpdateCopRuntimeStats(t *testing.T) { require.Nil(t, ctx.GetSessionVars().StmtCtx.RuntimeStatsColl) sr.rootPlanID = 1234 - sr.updateCopRuntimeStats(context.Background(), &copr.CopRuntimeStats{ExecDetails: execdetails.ExecDetails{CalleeAddress: "a"}}, 0) + sr.updateCopRuntimeStats(context.Background(), &copr.CopRuntimeStats{ExecDetails: execdetails.ExecDetails{DetailsNeedP90: execdetails.DetailsNeedP90{CalleeAddress: "a"}}}, 0) ctx.GetSessionVars().StmtCtx.RuntimeStatsColl = execdetails.NewRuntimeStatsColl(nil) i := uint64(1) @@ -46,13 +46,13 @@ func TestUpdateCopRuntimeStats(t *testing.T) { require.NotEqual(t, len(sr.copPlanIDs), len(sr.selectResp.GetExecutionSummaries())) - sr.updateCopRuntimeStats(context.Background(), &copr.CopRuntimeStats{ExecDetails: execdetails.ExecDetails{CalleeAddress: "callee"}}, 0) + sr.updateCopRuntimeStats(context.Background(), &copr.CopRuntimeStats{ExecDetails: execdetails.ExecDetails{DetailsNeedP90: execdetails.DetailsNeedP90{CalleeAddress: "callee"}}}, 0) require.False(t, ctx.GetSessionVars().StmtCtx.RuntimeStatsColl.ExistsCopStats(1234)) sr.copPlanIDs = []int{sr.rootPlanID} require.NotNil(t, ctx.GetSessionVars().StmtCtx.RuntimeStatsColl) require.Equal(t, len(sr.copPlanIDs), len(sr.selectResp.GetExecutionSummaries())) - sr.updateCopRuntimeStats(context.Background(), &copr.CopRuntimeStats{ExecDetails: execdetails.ExecDetails{CalleeAddress: "callee"}}, 0) + sr.updateCopRuntimeStats(context.Background(), &copr.CopRuntimeStats{ExecDetails: execdetails.ExecDetails{DetailsNeedP90: execdetails.DetailsNeedP90{CalleeAddress: "callee"}}}, 0) require.Equal(t, "tikv_task:{time:1ns, loops:1}", ctx.GetSessionVars().StmtCtx.RuntimeStatsColl.GetOrCreateCopStats(1234, "tikv").String()) } diff --git a/errors.toml b/errors.toml index e34de79661c62..df952cc7af45a 100644 --- a/errors.toml +++ b/errors.toml @@ -66,6 +66,11 @@ error = ''' restore met a invalid peer ''' +["BR:EBS:ErrRestoreRegionWithoutPeer"] +error = ''' +restore met a region without any peer +''' + ["BR:EBS:ErrRestoreTotalKVMismatch"] error = ''' restore total tikvs mismatch diff --git a/executor/adapter.go b/executor/adapter.go index 3dd0e0ce0877e..aaa7aa8c4b8c9 100644 --- a/executor/adapter.go +++ b/executor/adapter.go @@ -215,6 +215,7 @@ type PartitionTelemetryInfo struct { UseCreateIntervalPartition bool UseAddIntervalPartition bool UseDropIntervalPartition bool + UseCompactTablePartition bool } // AccountLockTelemetryInfo records account lock/unlock information during execution diff --git a/executor/aggregate.go b/executor/aggregate.go index 771d928c9bbad..30b86164ec371 100644 --- a/executor/aggregate.go +++ b/executor/aggregate.go @@ -244,6 +244,9 @@ func (d *HashAggIntermData) getPartialResultBatch(_ *stmtctx.StatementContext, p // Close implements the Executor Close interface. func (e *HashAggExec) Close() error { + if e.stats != nil { + defer e.ctx.GetSessionVars().StmtCtx.RuntimeStatsColl.RegisterStats(e.id, e.stats) + } if e.isUnparallelExec { var firstErr error e.childResult = nil @@ -1131,7 +1134,6 @@ func (e *HashAggExec) initRuntimeStats() { stats.PartialStats = make([]*AggWorkerStat, 0, stats.PartialConcurrency) stats.FinalStats = make([]*AggWorkerStat, 0, stats.FinalConcurrency) e.stats = stats - e.ctx.GetSessionVars().StmtCtx.RuntimeStatsColl.RegisterStats(e.id, e.stats) } } diff --git a/executor/autoidtest/autoid_test.go b/executor/autoidtest/autoid_test.go index 269f3966f8a01..f52f63b9c59a2 100644 --- a/executor/autoidtest/autoid_test.go +++ b/executor/autoidtest/autoid_test.go @@ -642,14 +642,23 @@ func TestAutoIDIncrementAndOffset(t *testing.T) { tk.MustExec(`insert into io(b) values (null),(null),(null)`) // AutoID allocation will take increment and offset into consideration. tk.MustQuery(`select b from io`).Check(testkit.Rows("10", "12", "14")) - // HandleID allocation will ignore the increment and offset. - tk.MustQuery(`select _tidb_rowid from io`).Check(testkit.Rows("15", "16", "17")) + if str == "" { + // HandleID allocation will ignore the increment and offset. + tk.MustQuery(`select _tidb_rowid from io`).Check(testkit.Rows("15", "16", "17")) + } else { + // Separate row id and auto inc id, increment and offset works on auto inc id + tk.MustQuery(`select _tidb_rowid from io`).Check(testkit.Rows("1", "2", "3")) + } tk.MustExec(`delete from io`) tk.Session().GetSessionVars().AutoIncrementIncrement = 10 tk.MustExec(`insert into io(b) values (null),(null),(null)`) tk.MustQuery(`select b from io`).Check(testkit.Rows("20", "30", "40")) - tk.MustQuery(`select _tidb_rowid from io`).Check(testkit.Rows("41", "42", "43")) + if str == "" { + tk.MustQuery(`select _tidb_rowid from io`).Check(testkit.Rows("41", "42", "43")) + } else { + tk.MustQuery(`select _tidb_rowid from io`).Check(testkit.Rows("4", "5", "6")) + } // Test invalid value. tk.Session().GetSessionVars().AutoIncrementIncrement = -1 @@ -711,27 +720,19 @@ func TestAlterTableAutoIDCache(t *testing.T) { require.NoError(t, err2) tk.MustExec("alter table t_473 auto_id_cache = 100") - tk.MustQuery("show table t_473 next_row_id").Check(testkit.Rows(fmt.Sprintf("test t_473 id %d AUTO_INCREMENT", val))) + tk.MustQuery("show table t_473 next_row_id").Check(testkit.Rows( + fmt.Sprintf("test t_473 id %d _TIDB_ROWID", val), + "test t_473 id 1 AUTO_INCREMENT", + )) tk.MustExec("insert into t_473 values ()") tk.MustQuery("select * from t_473").Check(testkit.Rows("1", fmt.Sprintf("%d", val))) - tk.MustQuery("show table t_473 next_row_id").Check(testkit.Rows(fmt.Sprintf("test t_473 id %d AUTO_INCREMENT", val+100))) - - // Note that auto_id_cache=1 use a different implementation. - tk.MustExec("alter table t_473 auto_id_cache = 1") - tk.MustQuery("show table t_473 next_row_id").Check(testkit.Rows(fmt.Sprintf("test t_473 id %d AUTO_INCREMENT", val+100))) - tk.MustExec("insert into t_473 values ()") - tk.MustQuery("select * from t_473").Check(testkit.Rows("1", fmt.Sprintf("%d", val), fmt.Sprintf("%d", val+100))) - tk.MustQuery("show table t_473 next_row_id").Check(testkit.Rows(fmt.Sprintf("test t_473 id %d AUTO_INCREMENT", val+101))) - - // alter table from auto_id_cache=1 to default will discard the IDs cached by the autoid service. - // This is because they are two component and TiDB can't tell the autoid service to "save position and exit". - tk.MustExec("alter table t_473 auto_id_cache = 20000") - tk.MustQuery("show table t_473 next_row_id").Check(testkit.Rows(fmt.Sprintf("test t_473 id %d AUTO_INCREMENT", val+4100))) - - tk.MustExec("insert into t_473 values ()") - tk.MustQuery("select * from t_473").Check(testkit.Rows("1", - fmt.Sprintf("%d", val), - fmt.Sprintf("%d", val+100), - fmt.Sprintf("%d", val+4100))) - tk.MustQuery("show table t_473 next_row_id").Check(testkit.Rows(fmt.Sprintf("test t_473 id %d AUTO_INCREMENT", val+24100))) + tk.MustQuery("show table t_473 next_row_id").Check(testkit.Rows( + fmt.Sprintf("test t_473 id %d _TIDB_ROWID", val+100), + "test t_473 id 1 AUTO_INCREMENT", + )) + + // Note that auto_id_cache=1 use a different implementation, switch between them is not allowed. + // TODO: relax this restriction and update the test case. + _, err = tk.Exec("alter table t_473 auto_id_cache = 1") + require.Error(t, err) } diff --git a/executor/batch_point_get.go b/executor/batch_point_get.go index 6f9710dd14f0d..ee9808700aaec 100644 --- a/executor/batch_point_get.go +++ b/executor/batch_point_get.go @@ -159,6 +159,9 @@ func MockNewCacheTableSnapShot(snapshot kv.Snapshot, memBuffer kv.MemBuffer) *ca // Close implements the Executor interface. func (e *BatchPointGetExec) Close() error { + if e.runtimeStats != nil { + defer e.ctx.GetSessionVars().StmtCtx.RuntimeStatsColl.RegisterStats(e.id, e.stats) + } if e.runtimeStats != nil && e.snapshot != nil { e.snapshot.SetOption(kv.CollectRuntimeStats, nil) } diff --git a/executor/builder.go b/executor/builder.go index 01bf8496fe77b..a046c6e386c9d 100644 --- a/executor/builder.go +++ b/executor/builder.go @@ -4906,7 +4906,6 @@ func (b *executorBuilder) buildBatchPointGet(plan *plannercore.BatchPointGetPlan SnapshotRuntimeStats: snapshotStats, } e.snapshot.SetOption(kv.CollectRuntimeStats, snapshotStats) - b.ctx.GetSessionVars().StmtCtx.RuntimeStatsColl.RegisterStats(e.id, e.stats) } if plan.IndexInfo != nil { @@ -5302,6 +5301,10 @@ func (b *executorBuilder) buildCompactTable(v *plannercore.CompactTable) Executo } partitionIDs = append(partitionIDs, partitionID) } + if b.Ti.PartitionTelemetry == nil { + b.Ti.PartitionTelemetry = &PartitionTelemetryInfo{} + } + b.Ti.PartitionTelemetry.UseCompactTablePartition = true } return &CompactTableTiFlashExec{ diff --git a/executor/distsql.go b/executor/distsql.go index 966a4a09ce357..aab5067a81b6a 100644 --- a/executor/distsql.go +++ b/executor/distsql.go @@ -724,6 +724,9 @@ func (e *IndexLookUpExecutor) buildTableReader(ctx context.Context, task *lookup // Close implements Exec Close interface. func (e *IndexLookUpExecutor) Close() error { + if e.stats != nil { + defer e.ctx.GetSessionVars().StmtCtx.RuntimeStatsColl.RegisterStats(e.id, e.stats) + } e.kvRanges = e.kvRanges[:0] if e.dummy { return nil @@ -808,7 +811,6 @@ func (e *IndexLookUpExecutor) initRuntimeStats() { indexScanBasicStats: &execdetails.BasicRuntimeStats{}, Concurrency: e.ctx.GetSessionVars().IndexLookupConcurrency(), } - e.ctx.GetSessionVars().StmtCtx.RuntimeStatsColl.RegisterStats(e.id, e.stats) } } @@ -876,7 +878,7 @@ func (w *indexWorker) fetchHandles(ctx context.Context, result distsql.SelectRes idxID := w.idxLookup.getIndexPlanRootID() if w.idxLookup.ctx.GetSessionVars().StmtCtx.RuntimeStatsColl != nil { if idxID != w.idxLookup.id && w.idxLookup.stats != nil { - w.idxLookup.ctx.GetSessionVars().StmtCtx.RuntimeStatsColl.RegisterStats(idxID, w.idxLookup.stats.indexScanBasicStats) + w.idxLookup.stats.indexScanBasicStats = w.idxLookup.ctx.GetSessionVars().StmtCtx.RuntimeStatsColl.GetBasicRuntimeStats(idxID) } } for { diff --git a/executor/executor.go b/executor/executor.go index 6aac622b223a4..169a19ec252e8 100644 --- a/executor/executor.go +++ b/executor/executor.go @@ -272,8 +272,7 @@ func newBaseExecutor(ctx sessionctx.Context, schema *expression.Schema, id int, } if ctx.GetSessionVars().StmtCtx.RuntimeStatsColl != nil { if e.id > 0 { - e.runtimeStats = &execdetails.BasicRuntimeStats{} - e.ctx.GetSessionVars().StmtCtx.RuntimeStatsColl.RegisterStats(id, e.runtimeStats) + e.runtimeStats = e.ctx.GetSessionVars().StmtCtx.RuntimeStatsColl.GetBasicRuntimeStats(id) } } if schema != nil { @@ -399,7 +398,7 @@ func (e *ShowNextRowIDExec) Next(ctx context.Context, req *chunk.Chunk) error { tblMeta := tbl.Meta() allocators := tbl.Allocators(e.ctx) - for _, alloc := range allocators { + for _, alloc := range allocators.Allocs { nextGlobalID, err := alloc.NextGlobalAutoID() if err != nil { return err @@ -407,7 +406,16 @@ func (e *ShowNextRowIDExec) Next(ctx context.Context, req *chunk.Chunk) error { var colName, idType string switch alloc.GetType() { - case autoid.RowIDAllocType, autoid.AutoIncrementType: + case autoid.RowIDAllocType: + idType = "_TIDB_ROWID" + if tblMeta.PKIsHandle { + if col := tblMeta.GetAutoIncrementColInfo(); col != nil { + colName = col.Name.O + } + } else { + colName = model.ExtraHandleName.O + } + case autoid.AutoIncrementType: idType = "AUTO_INCREMENT" if tblMeta.PKIsHandle { if col := tblMeta.GetAutoIncrementColInfo(); col != nil { diff --git a/executor/executor_test.go b/executor/executor_test.go index 5e8bb71daca6a..c73b3a3df7abd 100644 --- a/executor/executor_test.go +++ b/executor/executor_test.go @@ -1922,7 +1922,7 @@ func TestCheckIndex(t *testing.T) { tbInfo := tbl.Meta() alloc := autoid.NewAllocator(store, dbInfo.ID, tbInfo.ID, false, autoid.RowIDAllocType) - tb, err := tables.TableFromMeta(autoid.NewAllocators(alloc), tbInfo) + tb, err := tables.TableFromMeta(autoid.NewAllocators(false, alloc), tbInfo) require.NoError(t, err) _, err = se.Execute(context.Background(), "admin check index t c") diff --git a/executor/index_lookup_hash_join.go b/executor/index_lookup_hash_join.go index c54b60749601d..58bd84ff6e4d6 100644 --- a/executor/index_lookup_hash_join.go +++ b/executor/index_lookup_hash_join.go @@ -134,7 +134,6 @@ func (e *IndexNestedLoopHashJoin) Open(ctx context.Context) error { e.innerPtrBytes = make([][]byte, 0, 8) if e.runtimeStats != nil { e.stats = &indexLookUpJoinRuntimeStats{} - e.ctx.GetSessionVars().StmtCtx.RuntimeStatsColl.RegisterStats(e.id, e.stats) } e.finished.Store(false) return nil @@ -288,6 +287,9 @@ func (e *IndexNestedLoopHashJoin) isDryUpTasks(ctx context.Context) bool { // Close implements the IndexNestedLoopHashJoin Executor interface. func (e *IndexNestedLoopHashJoin) Close() error { + if e.stats != nil { + defer e.ctx.GetSessionVars().StmtCtx.RuntimeStatsColl.RegisterStats(e.id, e.stats) + } if e.cancelFunc != nil { e.cancelFunc() } diff --git a/executor/index_lookup_join.go b/executor/index_lookup_join.go index 05cc337d3d7ee..187e83cc0f763 100644 --- a/executor/index_lookup_join.go +++ b/executor/index_lookup_join.go @@ -171,7 +171,6 @@ func (e *IndexLookUpJoin) Open(ctx context.Context) error { e.finished.Store(false) if e.runtimeStats != nil { e.stats = &indexLookUpJoinRuntimeStats{} - e.ctx.GetSessionVars().StmtCtx.RuntimeStatsColl.RegisterStats(e.id, e.stats) } e.cancelFunc = nil return nil @@ -765,6 +764,9 @@ func (iw *innerWorker) hasNullInJoinKey(row chunk.Row) bool { // Close implements the Executor interface. func (e *IndexLookUpJoin) Close() error { + if e.stats != nil { + defer e.ctx.GetSessionVars().StmtCtx.RuntimeStatsColl.RegisterStats(e.id, e.stats) + } if e.cancelFunc != nil { e.cancelFunc() } diff --git a/executor/index_lookup_merge_join.go b/executor/index_lookup_merge_join.go index 8bd379944c825..e0fb176fff589 100644 --- a/executor/index_lookup_merge_join.go +++ b/executor/index_lookup_merge_join.go @@ -715,6 +715,9 @@ func (imw *innerMergeWorker) fetchNextInnerResult(ctx context.Context, task *loo // Close implements the Executor interface. func (e *IndexLookUpMergeJoin) Close() error { + if e.runtimeStats != nil { + defer e.ctx.GetSessionVars().StmtCtx.RuntimeStatsColl.RegisterStats(e.id, e.runtimeStats) + } if e.cancelFunc != nil { e.cancelFunc() e.cancelFunc = nil diff --git a/executor/index_merge_reader.go b/executor/index_merge_reader.go index 09e0885dee23b..cde353e2a64b2 100644 --- a/executor/index_merge_reader.go +++ b/executor/index_merge_reader.go @@ -470,7 +470,6 @@ func (e *IndexMergeReaderExecutor) initRuntimeStats() { e.stats = &IndexMergeRuntimeStat{ Concurrency: e.ctx.GetSessionVars().IndexLookupConcurrency(), } - e.ctx.GetSessionVars().StmtCtx.RuntimeStatsColl.RegisterStats(e.id, e.stats) } } @@ -704,6 +703,9 @@ func (e *IndexMergeReaderExecutor) handleHandlesFetcherPanic(ctx context.Context // Close implements Exec Close interface. func (e *IndexMergeReaderExecutor) Close() error { + if e.stats != nil { + defer e.ctx.GetSessionVars().StmtCtx.RuntimeStatsColl.RegisterStats(e.id, e.stats) + } if e.finished == nil { return nil } @@ -821,8 +823,7 @@ func (w *partialIndexWorker) fetchHandles( var basicStats *execdetails.BasicRuntimeStats if w.stats != nil { if w.idxID != 0 { - basicStats = &execdetails.BasicRuntimeStats{} - w.sc.GetSessionVars().StmtCtx.RuntimeStatsColl.RegisterStats(w.idxID, basicStats) + basicStats = w.sc.GetSessionVars().StmtCtx.RuntimeStatsColl.GetBasicRuntimeStats(w.idxID) } } for { diff --git a/executor/infoschema_reader.go b/executor/infoschema_reader.go index 1faf10d490856..472220bb2dcc6 100644 --- a/executor/infoschema_reader.go +++ b/executor/infoschema_reader.go @@ -386,7 +386,7 @@ func getAutoIncrementID(ctx sessionctx.Context, schema *model.DBInfo, tblInfo *m if err != nil { return 0, err } - return tbl.Allocators(ctx).Get(autoid.RowIDAllocType).Base() + 1, nil + return tbl.Allocators(ctx).Get(autoid.AutoIncrementType).Base() + 1, nil } func hasPriv(ctx sessionctx.Context, priv mysql.PrivilegeType) bool { diff --git a/executor/insert.go b/executor/insert.go index 7e17fabcfe957..36af152899bc3 100644 --- a/executor/insert.go +++ b/executor/insert.go @@ -337,6 +337,9 @@ func (e *InsertExec) Next(ctx context.Context, req *chunk.Chunk) error { // Close implements the Executor Close interface. func (e *InsertExec) Close() error { + if e.runtimeStats != nil && e.stats != nil { + defer e.ctx.GetSessionVars().StmtCtx.RuntimeStatsColl.RegisterStats(e.id, e.stats) + } defer e.memTracker.ReplaceBytesUsed(0) e.ctx.GetSessionVars().CurrInsertValues = chunk.Row{} e.ctx.GetSessionVars().CurrInsertBatchExtraCols = e.ctx.GetSessionVars().CurrInsertBatchExtraCols[0:0:0] diff --git a/executor/insert_common.go b/executor/insert_common.go index 5bb7feb2441da..7fcc0821ce82d 100644 --- a/executor/insert_common.go +++ b/executor/insert_common.go @@ -778,7 +778,8 @@ func (e *InsertValues) lazyAdjustAutoIncrementDatum(ctx context.Context, rows [] } // Use the value if it's not null and not 0. if recordID != 0 { - err = e.Table.Allocators(e.ctx).Get(autoid.RowIDAllocType).Rebase(ctx, recordID, true) + alloc := e.Table.Allocators(e.ctx).Get(autoid.AutoIncrementType) + err = alloc.Rebase(ctx, recordID, true) if err != nil { return nil, err } @@ -871,7 +872,7 @@ func (e *InsertValues) adjustAutoIncrementDatum(ctx context.Context, d types.Dat } // Use the value if it's not null and not 0. if recordID != 0 { - err = e.Table.Allocators(e.ctx).Get(autoid.RowIDAllocType).Rebase(ctx, recordID, true) + err = e.Table.Allocators(e.ctx).Get(autoid.AutoIncrementType).Rebase(ctx, recordID, true) if err != nil { return types.Datum{}, err } @@ -1096,7 +1097,6 @@ func (e *InsertValues) collectRuntimeStatsEnabled() bool { for _, fkc := range e.fkChecks { fkc.stats = e.stats.FKCheckStats } - e.ctx.GetSessionVars().StmtCtx.RuntimeStatsColl.RegisterStats(e.id, e.stats) } return true } diff --git a/executor/issuetest/executor_issue_test.go b/executor/issuetest/executor_issue_test.go index 78de8f0ef37d6..643339dd157d0 100644 --- a/executor/issuetest/executor_issue_test.go +++ b/executor/issuetest/executor_issue_test.go @@ -1240,3 +1240,46 @@ func TestIssue33214(t *testing.T) { } } } + +func TestIssue982(t *testing.T) { + store := testkit.CreateMockStore(t) + tk := testkit.NewTestKit(t, store) + tk.MustExec("use test") + tk.MustExec("drop table if exists t;") + tk.MustExec("create table t (c int auto_increment, key(c)) auto_id_cache 1;") + tk.MustExec("insert into t values();") + tk.MustExec("insert into t values();") + tk.MustQuery("select * from t;").Check(testkit.Rows("1", "2")) +} + +func TestIssue24627(t *testing.T) { + store := testkit.CreateMockStore(t) + tk := testkit.NewTestKit(t, store) + tk.MustExec("use test") + for _, sql := range []string{ + "create table test(id float primary key clustered AUTO_INCREMENT, col1 int);", + "create table test(id float primary key nonclustered AUTO_INCREMENT, col1 int) AUTO_ID_CACHE 1;", + } { + tk.MustExec("drop table if exists test;") + tk.MustExec(sql) + tk.MustExec("replace into test(col1) values(1);") + tk.MustExec("replace into test(col1) values(2);") + tk.MustQuery("select * from test;").Check(testkit.Rows("1 1", "2 2")) + tk.MustExec("drop table test") + } + + for _, sql := range []string{ + "create table test2(id double primary key clustered AUTO_INCREMENT, col1 int);", + "create table test2(id double primary key nonclustered AUTO_INCREMENT, col1 int) AUTO_ID_CACHE 1;", + } { + tk.MustExec(sql) + tk.MustExec("replace into test2(col1) values(1);") + tk.MustExec("insert into test2(col1) values(1);") + tk.MustExec("replace into test2(col1) values(1);") + tk.MustExec("insert into test2(col1) values(1);") + tk.MustExec("replace into test2(col1) values(1);") + tk.MustExec("replace into test2(col1) values(1);") + tk.MustQuery("select * from test2").Check(testkit.Rows("1 1", "2 1", "3 1", "4 1", "5 1", "6 1")) + tk.MustExec("drop table test2") + } +} diff --git a/executor/join.go b/executor/join.go index bcab7d9a4ea60..214e2edb1d440 100644 --- a/executor/join.go +++ b/executor/join.go @@ -183,6 +183,9 @@ func (e *HashJoinExec) Close() error { if e.stats != nil && e.rowContainer != nil { e.stats.hashStat = *e.rowContainer.stat } + if e.stats != nil { + defer e.ctx.GetSessionVars().StmtCtx.RuntimeStatsColl.RegisterStats(e.id, e.stats) + } err := e.baseExecutor.Close() return err } @@ -210,7 +213,6 @@ func (e *HashJoinExec) Open(ctx context.Context) error { e.stats = &hashJoinRuntimeStats{ concurrent: int(e.concurrency), } - e.ctx.GetSessionVars().StmtCtx.RuntimeStatsColl.RegisterStats(e.id, e.stats) } return nil } @@ -1271,7 +1273,6 @@ func (e *NestedLoopApplyExec) Close() error { e.memTracker = nil if e.runtimeStats != nil { runtimeStats := newJoinRuntimeStats() - e.ctx.GetSessionVars().StmtCtx.RuntimeStatsColl.RegisterStats(e.id, runtimeStats) if e.canUseCache { var hitRatio float64 if e.cacheAccessCounter > 0 { @@ -1282,6 +1283,7 @@ func (e *NestedLoopApplyExec) Close() error { runtimeStats.setCacheInfo(false, 0) } runtimeStats.SetConcurrencyInfo(execdetails.NewConcurrencyInfo("Concurrency", 0)) + defer e.ctx.GetSessionVars().StmtCtx.RuntimeStatsColl.RegisterStats(e.id, runtimeStats) } return e.outerExec.Close() } @@ -1539,6 +1541,17 @@ func (e *joinRuntimeStats) Tp() int { return execdetails.TpJoinRuntimeStats } +func (e *joinRuntimeStats) Clone() execdetails.RuntimeStats { + newJRS := &joinRuntimeStats{ + RuntimeStatsWithConcurrencyInfo: e.RuntimeStatsWithConcurrencyInfo, + applyCache: e.applyCache, + cache: e.cache, + hasHashStat: e.hasHashStat, + hashStat: e.hashStat, + } + return newJRS +} + type hashJoinRuntimeStats struct { fetchAndBuildHashTable time.Duration hashStat hashStatistic diff --git a/executor/load_data.go b/executor/load_data.go index e11137c3916ae..a5db464ce705e 100644 --- a/executor/load_data.go +++ b/executor/load_data.go @@ -80,6 +80,9 @@ func (e *LoadDataExec) Next(ctx context.Context, req *chunk.Chunk) error { // Close implements the Executor Close interface. func (e *LoadDataExec) Close() error { + if e.runtimeStats != nil && e.loadDataInfo != nil && e.loadDataInfo.stats != nil { + defer e.ctx.GetSessionVars().StmtCtx.RuntimeStatsColl.RegisterStats(e.id, e.loadDataInfo.stats) + } return nil } diff --git a/executor/parallel_apply.go b/executor/parallel_apply.go index 2c4499b14818c..a0d418cc0e441 100644 --- a/executor/parallel_apply.go +++ b/executor/parallel_apply.go @@ -176,7 +176,6 @@ func (e *ParallelNestedLoopApplyExec) Close() error { if e.runtimeStats != nil { runtimeStats := newJoinRuntimeStats() - e.ctx.GetSessionVars().StmtCtx.RuntimeStatsColl.RegisterStats(e.id, runtimeStats) if e.useCache { var hitRatio float64 if e.cacheAccessCounter > 0 { @@ -187,6 +186,7 @@ func (e *ParallelNestedLoopApplyExec) Close() error { runtimeStats.setCacheInfo(false, 0) } runtimeStats.SetConcurrencyInfo(execdetails.NewConcurrencyInfo("Concurrency", e.concurrency)) + defer e.ctx.GetSessionVars().StmtCtx.RuntimeStatsColl.RegisterStats(e.id, runtimeStats) } return err } diff --git a/executor/point_get.go b/executor/point_get.go index e83c5f32e0927..3e3cddb08d9ba 100644 --- a/executor/point_get.go +++ b/executor/point_get.go @@ -80,7 +80,6 @@ func (b *executorBuilder) buildPointGet(p *plannercore.PointGetPlan) Executor { SnapshotRuntimeStats: snapshotStats, } e.snapshot.SetOption(kv.CollectRuntimeStats, snapshotStats) - b.ctx.GetSessionVars().StmtCtx.RuntimeStatsColl.RegisterStats(e.id, e.stats) } if p.IndexInfo != nil { @@ -194,6 +193,9 @@ func (e *PointGetExecutor) Open(context.Context) error { // Close implements the Executor interface. func (e *PointGetExecutor) Close() error { + if e.stats != nil { + defer e.ctx.GetSessionVars().StmtCtx.RuntimeStatsColl.RegisterStats(e.id, e.stats) + } if e.runtimeStats != nil && e.snapshot != nil { e.snapshot.SetOption(kv.CollectRuntimeStats, nil) } diff --git a/executor/replace.go b/executor/replace.go index 221cbf87b2504..f028d5e6db32c 100644 --- a/executor/replace.go +++ b/executor/replace.go @@ -43,6 +43,9 @@ type ReplaceExec struct { // Close implements the Executor Close interface. func (e *ReplaceExec) Close() error { e.setMessage() + if e.runtimeStats != nil && e.stats != nil { + defer e.ctx.GetSessionVars().StmtCtx.RuntimeStatsColl.RegisterStats(e.id, e.stats) + } if e.SelectExec != nil { return e.SelectExec.Close() } diff --git a/executor/seqtest/seq_executor_test.go b/executor/seqtest/seq_executor_test.go index 7f16fd68da5e7..bf78e40e7ac3d 100644 --- a/executor/seqtest/seq_executor_test.go +++ b/executor/seqtest/seq_executor_test.go @@ -773,43 +773,45 @@ func HelperTestAdminShowNextID(t *testing.T, store kv.Storage, str string) { tk.MustExec("create table t(id int, c int)") // Start handle is 1. r := tk.MustQuery(str + " t next_row_id") - r.Check(testkit.Rows("test t _tidb_rowid 1 AUTO_INCREMENT")) + r.Check(testkit.Rows("test t _tidb_rowid 1 _TIDB_ROWID")) // Row ID is step + 1. tk.MustExec("insert into t values(1, 1)") r = tk.MustQuery(str + " t next_row_id") - r.Check(testkit.Rows("test t _tidb_rowid 11 AUTO_INCREMENT")) + r.Check(testkit.Rows("test t _tidb_rowid 11 _TIDB_ROWID")) // Row ID is original + step. for i := 0; i < int(step); i++ { tk.MustExec("insert into t values(10000, 1)") } r = tk.MustQuery(str + " t next_row_id") - r.Check(testkit.Rows("test t _tidb_rowid 21 AUTO_INCREMENT")) + r.Check(testkit.Rows("test t _tidb_rowid 21 _TIDB_ROWID")) tk.MustExec("drop table t") // test for a table with the primary key tk.MustExec("create table tt(id int primary key auto_increment, c int)") // Start handle is 1. r = tk.MustQuery(str + " tt next_row_id") - r.Check(testkit.Rows("test tt id 1 AUTO_INCREMENT")) + r.Check(testkit.Rows("test tt id 1 _TIDB_ROWID", "test tt id 1 AUTO_INCREMENT")) // After rebasing auto ID, row ID is 20 + step + 1. tk.MustExec("insert into tt values(20, 1)") r = tk.MustQuery(str + " tt next_row_id") - r.Check(testkit.Rows("test tt id 31 AUTO_INCREMENT")) + r.Check(testkit.Rows("test tt id 31 _TIDB_ROWID", "test tt id 1 AUTO_INCREMENT")) // test for renaming the table tk.MustExec("drop database if exists test1") tk.MustExec("create database test1") tk.MustExec("rename table test.tt to test1.tt") tk.MustExec("use test1") r = tk.MustQuery(str + " tt next_row_id") - r.Check(testkit.Rows("test1 tt id 31 AUTO_INCREMENT")) + r.Check(testkit.Rows("test1 tt id 31 _TIDB_ROWID", "test1 tt id 1 AUTO_INCREMENT")) tk.MustExec("insert test1.tt values ()") r = tk.MustQuery(str + " tt next_row_id") - r.Check(testkit.Rows("test1 tt id 41 AUTO_INCREMENT")) + r.Check(testkit.Rows("test1 tt id 41 _TIDB_ROWID", "test1 tt id 1 AUTO_INCREMENT")) tk.MustExec("drop table tt") tk.MustExec("drop table if exists t;") tk.MustExec("create table t (a int auto_increment primary key nonclustered, b int);") - tk.MustQuery("show table t next_row_id;").Check(testkit.Rows("test1 t _tidb_rowid 1 AUTO_INCREMENT")) + tk.MustQuery("show table t next_row_id;").Check(testkit.Rows( + "test1 t _tidb_rowid 1 _TIDB_ROWID", + "test1 t _tidb_rowid 1 AUTO_INCREMENT")) tk.MustExec("set @@allow_auto_random_explicit_insert = true") @@ -830,19 +832,19 @@ func HelperTestAdminShowNextID(t *testing.T, store kv.Storage, str string) { // Test for a sequence. tk.MustExec("create sequence seq1 start 15 cache 57") r = tk.MustQuery(str + " seq1 next_row_id") - r.Check(testkit.Rows("test1 seq1 _tidb_rowid 1 AUTO_INCREMENT", "test1 seq1 15 SEQUENCE")) + r.Check(testkit.Rows("test1 seq1 _tidb_rowid 1 _TIDB_ROWID", "test1 seq1 15 SEQUENCE")) r = tk.MustQuery("select nextval(seq1)") r.Check(testkit.Rows("15")) r = tk.MustQuery(str + " seq1 next_row_id") - r.Check(testkit.Rows("test1 seq1 _tidb_rowid 1 AUTO_INCREMENT", "test1 seq1 72 SEQUENCE")) + r.Check(testkit.Rows("test1 seq1 _tidb_rowid 1 _TIDB_ROWID", "test1 seq1 72 SEQUENCE")) r = tk.MustQuery("select nextval(seq1)") r.Check(testkit.Rows("16")) r = tk.MustQuery(str + " seq1 next_row_id") - r.Check(testkit.Rows("test1 seq1 _tidb_rowid 1 AUTO_INCREMENT", "test1 seq1 72 SEQUENCE")) + r.Check(testkit.Rows("test1 seq1 _tidb_rowid 1 _TIDB_ROWID", "test1 seq1 72 SEQUENCE")) r = tk.MustQuery("select setval(seq1, 96)") r.Check(testkit.Rows("96")) r = tk.MustQuery(str + " seq1 next_row_id") - r.Check(testkit.Rows("test1 seq1 _tidb_rowid 1 AUTO_INCREMENT", "test1 seq1 97 SEQUENCE")) + r.Check(testkit.Rows("test1 seq1 _tidb_rowid 1 _TIDB_ROWID", "test1 seq1 97 SEQUENCE")) } func TestNoHistoryWhenDisableRetry(t *testing.T) { diff --git a/executor/update.go b/executor/update.go index cf0a6ae2e33f4..0068392653cdd 100644 --- a/executor/update.go +++ b/executor/update.go @@ -434,6 +434,7 @@ func (e *UpdateExec) Close() error { if err == nil && txn.Valid() && txn.GetSnapshot() != nil { txn.GetSnapshot().SetOption(kv.CollectRuntimeStats, nil) } + defer e.ctx.GetSessionVars().StmtCtx.RuntimeStatsColl.RegisterStats(e.id, e.stats) } return e.children[0].Close() } @@ -463,7 +464,6 @@ func (e *UpdateExec) collectRuntimeStatsEnabled() bool { SnapshotRuntimeStats: &txnsnapshot.SnapshotRuntimeStats{}, AllocatorRuntimeStats: autoid.NewAllocatorRuntimeStats(), } - e.ctx.GetSessionVars().StmtCtx.RuntimeStatsColl.RegisterStats(e.id, e.stats) } return true } diff --git a/executor/write.go b/executor/write.go index 4c36884cc570d..363bb097fd02c 100644 --- a/executor/write.go +++ b/executor/write.go @@ -109,7 +109,7 @@ func updateRecord(ctx context.Context, sctx sessionctx.Context, h kv.Handle, old if err != nil { return false, err } - if err = t.Allocators(sctx).Get(autoid.RowIDAllocType).Rebase(ctx, recordID, true); err != nil { + if err = t.Allocators(sctx).Get(autoid.AutoIncrementType).Rebase(ctx, recordID, true); err != nil { return false, err } } diff --git a/infoschema/builder.go b/infoschema/builder.go index 8ff50a8b50435..67153fcc5f3bd 100644 --- a/infoschema/builder.go +++ b/infoschema/builder.go @@ -693,18 +693,23 @@ func (b *Builder) applyCreateTable(m *meta.Meta, dbInfo *model.DBInfo, tableID i ConvertCharsetCollateToLowerCaseIfNeed(tblInfo) ConvertOldVersionUTF8ToUTF8MB4IfNeed(tblInfo) - if len(allocs) == 0 { + if len(allocs.Allocs) == 0 { allocs = autoid.NewAllocatorsFromTblInfo(b.store, dbInfo.ID, tblInfo) } else { tblVer := autoid.AllocOptionTableInfoVersion(tblInfo.Version) switch tp { case model.ActionRebaseAutoID, model.ActionModifyTableAutoIdCache: idCacheOpt := autoid.CustomAutoIncCacheOption(tblInfo.AutoIdCache) - newAlloc := autoid.NewAllocator(b.store, dbInfo.ID, tblInfo.ID, tblInfo.IsAutoIncColUnsigned(), autoid.RowIDAllocType, tblVer, idCacheOpt) - allocs = append(allocs, newAlloc) + // If the allocator type might be AutoIncrementType, create both AutoIncrementType + // and RowIDAllocType allocator for it. Because auto id and row id could share the same allocator. + // Allocate auto id may route to allocate row id, if row id allocator is nil, the program panic! + for _, tp := range [2]autoid.AllocatorType{autoid.AutoIncrementType, autoid.RowIDAllocType} { + newAlloc := autoid.NewAllocator(b.store, dbInfo.ID, tblInfo.ID, tblInfo.IsAutoIncColUnsigned(), tp, tblVer, idCacheOpt) + allocs = allocs.Append(newAlloc) + } case model.ActionRebaseAutoRandomBase: newAlloc := autoid.NewAllocator(b.store, dbInfo.ID, tblInfo.ID, tblInfo.IsAutoRandomBitColUnsigned(), autoid.AutoRandomType, tblVer) - allocs = append(allocs, newAlloc) + allocs = allocs.Append(newAlloc) case model.ActionModifyColumn: // Change column attribute from auto_increment to auto_random. if tblInfo.ContainsAutoRandomBits() && allocs.Get(autoid.AutoRandomType) == nil { @@ -713,7 +718,7 @@ func (b *Builder) applyCreateTable(m *meta.Meta, dbInfo *model.DBInfo, tableID i return a.GetType() != autoid.AutoIncrementType && a.GetType() != autoid.RowIDAllocType }) newAlloc := autoid.NewAllocator(b.store, dbInfo.ID, tblInfo.ID, tblInfo.IsAutoRandomBitColUnsigned(), autoid.AutoRandomType, tblVer) - allocs = append(allocs, newAlloc) + allocs = allocs.Append(newAlloc) } } } diff --git a/infoschema/infoschema.go b/infoschema/infoschema.go index 040dbd239eef6..11c9bd8b0e7af 100644 --- a/infoschema/infoschema.go +++ b/infoschema/infoschema.go @@ -270,7 +270,7 @@ func (is *infoSchema) TableByID(id int64) (val table.Table, ok bool) { func (is *infoSchema) AllocByID(id int64) (autoid.Allocators, bool) { tbl, ok := is.TableByID(id) if !ok { - return nil, false + return autoid.Allocators{}, false } return tbl.Allocators(nil), true } diff --git a/infoschema/tables.go b/infoschema/tables.go index 8df6cab9cb84c..d76d8b8be60b0 100644 --- a/infoschema/tables.go +++ b/infoschema/tables.go @@ -2123,7 +2123,7 @@ func (it *infoschemaTable) UpdateRecord(gctx context.Context, ctx sessionctx.Con // Allocators implements table.Table Allocators interface. func (it *infoschemaTable) Allocators(_ sessionctx.Context) autoid.Allocators { - return nil + return autoid.Allocators{} } // Meta implements table.Table Meta interface. @@ -2206,7 +2206,7 @@ func (vt *VirtualTable) UpdateRecord(ctx context.Context, sctx sessionctx.Contex // Allocators implements table.Table Allocators interface. func (vt *VirtualTable) Allocators(_ sessionctx.Context) autoid.Allocators { - return nil + return autoid.Allocators{} } // Meta implements table.Table Meta interface. diff --git a/meta/autoid/autoid.go b/meta/autoid/autoid.go index def3245bb2da3..2a181a088d802 100644 --- a/meta/autoid/autoid.go +++ b/meta/autoid/autoid.go @@ -205,16 +205,36 @@ type Allocator interface { } // Allocators represents a set of `Allocator`s. -type Allocators []Allocator +type Allocators struct { + SepAutoInc bool + Allocs []Allocator +} // NewAllocators packs multiple `Allocator`s into Allocators. -func NewAllocators(allocators ...Allocator) Allocators { - return allocators +func NewAllocators(sepAutoInc bool, allocators ...Allocator) Allocators { + return Allocators{ + SepAutoInc: sepAutoInc, + Allocs: allocators, + } +} + +// Append add an allocator to the allocators. +func (all Allocators) Append(a Allocator) Allocators { + return Allocators{ + SepAutoInc: all.SepAutoInc, + Allocs: append(all.Allocs, a), + } } // Get returns the Allocator according to the AllocatorType. func (all Allocators) Get(allocType AllocatorType) Allocator { - for _, a := range all { + if !all.SepAutoInc { + if allocType == AutoIncrementType { + allocType = RowIDAllocType + } + } + + for _, a := range all.Allocs { if a.GetType() == allocType { return a } @@ -224,13 +244,16 @@ func (all Allocators) Get(allocType AllocatorType) Allocator { // Filter filters all the allocators that match pred. func (all Allocators) Filter(pred func(Allocator) bool) Allocators { - var ret Allocators - for _, a := range all { + var ret []Allocator + for _, a := range all.Allocs { if pred(a) { ret = append(ret, a) } } - return ret + return Allocators{ + SepAutoInc: all.SepAutoInc, + Allocs: ret, + } } type allocator struct { @@ -593,7 +616,7 @@ func NewAllocator(store kv.Storage, dbID, tbID int64, isUnsigned bool, } // Use the MySQL compatible AUTO_INCREMENT mode. - if allocType == RowIDAllocType && alloc.customStep && alloc.step == 1 { + if allocType == AutoIncrementType && alloc.customStep && alloc.step == 1 && alloc.tbVersion >= model.TableInfoVersion5 { alloc1 := newSinglePointAlloc(store, dbID, tbID, isUnsigned) if alloc1 != nil { return alloc1 @@ -630,6 +653,10 @@ func NewAllocatorsFromTblInfo(store kv.Storage, schemaID int64, tblInfo *model.T alloc := NewAllocator(store, dbID, tblInfo.ID, tblInfo.IsAutoIncColUnsigned(), RowIDAllocType, idCacheOpt, tblVer) allocs = append(allocs, alloc) } + if hasAutoIncID { + alloc := NewAllocator(store, dbID, tblInfo.ID, tblInfo.IsAutoIncColUnsigned(), AutoIncrementType, idCacheOpt, tblVer) + allocs = append(allocs, alloc) + } hasAutoRandID := tblInfo.ContainsAutoRandomBits() if hasAutoRandID { alloc := NewAllocator(store, dbID, tblInfo.ID, tblInfo.IsAutoRandomBitColUnsigned(), AutoRandomType, idCacheOpt, tblVer) @@ -638,7 +665,7 @@ func NewAllocatorsFromTblInfo(store kv.Storage, schemaID int64, tblInfo *model.T if tblInfo.IsSequence() { allocs = append(allocs, NewSequenceAllocator(store, dbID, tblInfo.ID, tblInfo.Sequence)) } - return NewAllocators(allocs...) + return NewAllocators(tblInfo.SepAutoInc(), allocs...) } // Alloc implements autoid.Allocator Alloc interface. @@ -839,7 +866,7 @@ func (alloc *allocator) alloc4Signed(ctx context.Context, n uint64, increment, o var newBase, newEnd int64 startTime := time.Now() nextStep := alloc.step - if !alloc.customStep { + if !alloc.customStep && alloc.end > 0 { // Although it may skip a segment here, we still think it is consumed. consumeDur := startTime.Sub(alloc.lastAllocTime) nextStep = NextStep(alloc.step, consumeDur) diff --git a/meta/autoid/autoid_service.go b/meta/autoid/autoid_service.go index 2942f3281b769..e524397e0041f 100644 --- a/meta/autoid/autoid_service.go +++ b/meta/autoid/autoid_service.go @@ -236,5 +236,5 @@ func (sp *singlePointAlloc) NextGlobalAutoID() (int64, error) { } func (*singlePointAlloc) GetType() AllocatorType { - return RowIDAllocType + return AutoIncrementType } diff --git a/meta/meta_autoid.go b/meta/meta_autoid.go index 18d384b2b25a7..5763aa268051a 100644 --- a/meta/meta_autoid.go +++ b/meta/meta_autoid.go @@ -102,7 +102,7 @@ type autoIDAccessors struct { access autoIDAccessor } -const sepAutoIncVer = model.TableInfoVersion4 + 1 +const sepAutoIncVer = model.TableInfoVersion5 // Get implements the interface AutoIDAccessors. func (a *autoIDAccessors) Get() (autoIDs AutoIDGroup, err error) { diff --git a/metrics/telemetry.go b/metrics/telemetry.go index 486a2d43a0c59..7460ca5ceb04c 100644 --- a/metrics/telemetry.go +++ b/metrics/telemetry.go @@ -155,6 +155,13 @@ var ( Name: "flashback_cluster_usage", Help: "Counter of usage of flashback cluster", }) + TelemetryCompactPartitionCnt = prometheus.NewCounter( + prometheus.CounterOpts{ + Namespace: "tidb", + Subsystem: "telemetry", + Name: "compact_partition_usage", + Help: "Counter of compact table partition", + }) ) // readCounter reads the value of a prometheus.Counter. @@ -254,6 +261,7 @@ type TablePartitionUsageCounter struct { TablePartitionCreateIntervalPartitionsCnt int64 `json:"table_partition_create_interval_partitions_cnt"` TablePartitionAddIntervalPartitionsCnt int64 `json:"table_partition_add_interval_partitions_cnt"` TablePartitionDropIntervalPartitionsCnt int64 `json:"table_partition_drop_interval_partitions_cnt"` + TablePartitionComactCnt int64 `json:"table_TablePartitionComactCnt"` } // ExchangePartitionUsageCounter records the usages of exchange partition. @@ -291,6 +299,7 @@ func (c TablePartitionUsageCounter) Cal(rhs TablePartitionUsageCounter) TablePar TablePartitionCreateIntervalPartitionsCnt: c.TablePartitionCreateIntervalPartitionsCnt - rhs.TablePartitionCreateIntervalPartitionsCnt, TablePartitionAddIntervalPartitionsCnt: c.TablePartitionAddIntervalPartitionsCnt - rhs.TablePartitionAddIntervalPartitionsCnt, TablePartitionDropIntervalPartitionsCnt: c.TablePartitionDropIntervalPartitionsCnt - rhs.TablePartitionDropIntervalPartitionsCnt, + TablePartitionComactCnt: c.TablePartitionComactCnt - rhs.TablePartitionComactCnt, } } @@ -326,6 +335,7 @@ func GetTablePartitionCounter() TablePartitionUsageCounter { TablePartitionCreateIntervalPartitionsCnt: readCounter(TelemetryTablePartitionCreateIntervalPartitionsCnt), TablePartitionAddIntervalPartitionsCnt: readCounter(TelemetryTablePartitionAddIntervalPartitionsCnt), TablePartitionDropIntervalPartitionsCnt: readCounter(TelemetryTablePartitionDropIntervalPartitionsCnt), + TablePartitionComactCnt: readCounter(TelemetryCompactPartitionCnt), } } diff --git a/parser/model/model.go b/parser/model/model.go index e38e5b368f4a1..ba7c46bcd6333 100644 --- a/parser/model/model.go +++ b/parser/model/model.go @@ -446,14 +446,16 @@ const ( // However, the convert is missed in some scenarios before v2.1.9, so for all those tables prior to TableInfoVersion3, their // charsets / collations will be converted to lower-case while loading from the storage. TableInfoVersion3 = uint16(3) - // TableInfoVersion4 indicates that the auto_increment allocator in TiDB has been separated from - // _tidb_rowid allocator. This version is introduced to preserve the compatibility of old tables: - // the tables with version < TableInfoVersion4 still use a single allocator for auto_increment and _tidb_rowid. - // Also see https://github.com/pingcap/tidb/issues/982. + // TableInfoVersion4 is not used. TableInfoVersion4 = uint16(4) + // TableInfoVersion5 indicates that the auto_increment allocator in TiDB has been separated from + // _tidb_rowid allocator when AUTO_ID_CACHE is 1. This version is introduced to preserve the compatibility of old tables: + // the tables with version <= TableInfoVersion4 still use a single allocator for auto_increment and _tidb_rowid. + // Also see https://github.com/pingcap/tidb/issues/982. + TableInfoVersion5 = uint16(5) // CurrLatestTableInfoVersion means the latest table info in the current TiDB. - CurrLatestTableInfoVersion = TableInfoVersion4 + CurrLatestTableInfoVersion = TableInfoVersion5 ) // ExtraHandleName is the name of ExtraHandle Column. @@ -552,6 +554,11 @@ type TableInfo struct { TTLInfo *TTLInfo `json:"ttl_info"` } +// SepAutoInc decides whether _rowid and auto_increment id use separate allocator. +func (t *TableInfo) SepAutoInc() bool { + return t.Version >= TableInfoVersion5 && t.AutoIdCache == 1 +} + // TableCacheStatusType is the type of the table cache status type TableCacheStatusType int diff --git a/planner/core/integration_test.go b/planner/core/integration_test.go index 2d119d8c99d5c..b50cc21397fa1 100644 --- a/planner/core/integration_test.go +++ b/planner/core/integration_test.go @@ -1365,16 +1365,18 @@ func TestViewHintScope(t *testing.T) { tk.MustExec("use test") tk.MustExec("set tidb_cost_model_version=2") - tk.MustExec("drop view if exists v, v1, v2, v3") - tk.MustExec("drop table if exists t, t1, t2") + tk.MustExec("drop view if exists v, v1, v2, v3, v4") + tk.MustExec("drop table if exists t, t1, t2, t3, t4") tk.MustExec("create table t(a int, b int);") tk.MustExec("create table t1(a int, b int);") tk.MustExec("create table t2(a int, b int);") tk.MustExec("create table t3(a int, b int)") + tk.MustExec("create table t4(a int, b int, index idx_a(a), index idx_b(b))") tk.MustExec("create definer='root'@'localhost' view v as select t.a, t.b from t join (select count(*) as a from t1 join t2 join t3 where t1.b=t2.b and t2.a = t3.a group by t2.a) tt on t.a = tt.a;") tk.MustExec("create definer='root'@'localhost' view v1 as select t.a, t.b from t join (select count(*) as a from t1 join v on t1.b=v.b group by v.a) tt on t.a = tt.a;") tk.MustExec("create definer='root'@'localhost' view v2 as select t.a, t.b from t join (select count(*) as a from t1 join v1 on t1.b=v1.b group by v1.a) tt on t.a = tt.a;") tk.MustExec("create definer='root'@'localhost' view v3 as select /*+ merge_join(t) */ t.a, t.b from t join (select /*+ stream_agg() */ count(*) as a from t1 join v1 on t1.b=v1.b group by v1.a) tt on t.a = tt.a;") + tk.MustExec("create definer='root'@'localhost' view v4 as select * from t4 where a > 2 and b > 3;") var input []string var output []struct { @@ -1403,7 +1405,7 @@ func TestViewHintWithBinding(t *testing.T) { tk.MustExec("use test") tk.MustExec("set tidb_cost_model_version=2") tk.MustExec("drop view if exists v, v1") - tk.MustExec("drop table if exists t, t1, t2") + tk.MustExec("drop table if exists t, t1, t2, t3") tk.MustExec("create table t(a int, b int);") tk.MustExec("create table t1(a int, b int);") tk.MustExec("create table t2(a int, b int);") diff --git a/planner/core/logical_plan_builder.go b/planner/core/logical_plan_builder.go index 0d314644ad046..ebabe1ba95795 100644 --- a/planner/core/logical_plan_builder.go +++ b/planner/core/logical_plan_builder.go @@ -4438,8 +4438,7 @@ func (b *PlanBuilder) buildDataSource(ctx context.Context, tn *ast.TableName, as // Because of the nested views, so we should check the left table list in hint when build the data source from the view inside the current view. currentQBNameMap4View[qbName] = viewQBNameHintTable[1:] currentViewHints[qbName] = b.hintProcessor.QbHints4View[qbName] - delete(b.hintProcessor.QbNameMap4View, qbName) - delete(b.hintProcessor.QbHints4View, qbName) + b.hintProcessor.QbNameUsed4View[qbName] = struct{}{} } } return b.BuildDataSourceFromView(ctx, dbName, tableInfo, currentQBNameMap4View, currentViewHints) @@ -5042,6 +5041,7 @@ func (b *PlanBuilder) BuildDataSourceFromView(ctx context.Context, dbName model. hintProcessor.QbNameMap4View = qbNameMap4View hintProcessor.QbHints4View = viewHints + hintProcessor.QbNameUsed4View = make(map[string]struct{}) hintProcessor.QbHints = currentQbHints hintProcessor.QbNameMap = currentQbNameMap @@ -5050,6 +5050,7 @@ func (b *PlanBuilder) BuildDataSourceFromView(ctx context.Context, dbName model. b.hintProcessor = hintProcessor b.ctx.GetSessionVars().PlannerSelectBlockAsName = make([]ast.HintTable, hintProcessor.MaxSelectStmtOffset()+1) defer func() { + b.hintProcessor.HandleUnusedViewHints() b.hintProcessor = originHintProcessor b.ctx.GetSessionVars().PlannerSelectBlockAsName = originPlannerSelectBlockAsName }() diff --git a/planner/core/testdata/integration_suite_in.json b/planner/core/testdata/integration_suite_in.json index bcce484092644..df990e52c65eb 100644 --- a/planner/core/testdata/integration_suite_in.json +++ b/planner/core/testdata/integration_suite_in.json @@ -667,8 +667,8 @@ // Hint for view v1 "explain format = 'brief' select /*+ qb_name(qb_v1_2, v1@sel_1 .@sel_2), merge_join(t1@qb_v1_2) */ * from v1;", "explain format = 'brief' select /*+ qb_name(qb_v1_2, v1@sel_1 .@sel_2), merge_join(t1@qb_v1_2), stream_agg(@qb_v1_2), qb_name(qb_v1_1, v1@sel_1 .@sel_1), merge_join(t@qb_v1_1) */ * from v1;", - "explain format = 'brief' select /*+ qb_name(qb_v1_2, v2@sel_1 . v1@sel_1 .@sel_2), merge_join(t1@qb_v1_2) */ * from v2;", - "explain format = 'brief' select /*+ qb_name(qb_v1_2, v2@sel_1 . v1@sel_1 .@sel_2), merge_join(t1@qb_v1_2), stream_agg(@qb_v1_2), qb_name(qb_v1_1, v2@sel_1 . v1@sel_1 .@sel_1), merge_join(t@qb_v1_1) */ * from v2;", + "explain format = 'brief' select /*+ qb_name(qb_v1_2, v2@sel_1 . v1@sel_2 .@sel_2), merge_join(t1@qb_v1_2) */ * from v2;", + "explain format = 'brief' select /*+ qb_name(qb_v1_2, v2@sel_1 . v1@sel_2 .@sel_2), merge_join(t1@qb_v1_2), stream_agg(@qb_v1_2), qb_name(qb_v1_1, v2@sel_1 . v1@sel_2 .@sel_1), merge_join(t@qb_v1_1) */ * from v2;", // Hint for view v2 "explain format = 'brief' select /*+ qb_name(qb_v2_2, v2@sel_1 .@sel_2), merge_join(t1@qb_v2_2) */ * from v2;", @@ -684,7 +684,6 @@ "explain format = 'brief' select /*+ qb_name(qb_v, v2@sel_1 .v1@sel_2 .v@sel_2 .@sel_2), qb_name(qb_v, v2@sel_1 .v1@sel_2 .v@sel_2 .@sel_1), merge_join(t1@qb_v) */ * from v2;", // Set the unappeared view name - // TODO: add the warning for the unused the view hints "explain format = 'brief' select /*+ qb_name(qb_v1_2, v@sel_1 .@sel_2), merge_join(t1@qb_v1_2) */ * from v1;", "explain format = 'brief' select /*+ qb_name(qb_v1_2, v2@sel_1 . v@sel_1 .@sel_2), merge_join(t1@qb_v1_2) */ * from v2;", @@ -694,18 +693,17 @@ // Tht view hint isn't set in the first query block. "explain format = 'brief' select * from (select /*+ qb_name(qb_v_2, v@sel_1 .@sel_2), merge_join(t1@qb_v_2) */ * from v) t;", - "explain format = 'brief' select * from (select /*+ qb_name(qb_v_2, v@sel_1 .@sel_2), merge_join(t1@qb_v_2), stream_agg(@qb_v_2), qb_name(qb_v_1, v@sel_1 .@sel1), merge_join(t@qb_v_1) */ * from v) t;", + "explain format = 'brief' select * from (select /*+ qb_name(qb_v_2, v.@sel_2), merge_join(t1@qb_v_2), stream_agg(@qb_v_2), qb_name(qb_v_1, v@sel_1 .@sel1), merge_join(t@qb_v_1) */ * from v) t;", "explain format = 'brief' select * from (select /*+ qb_name(qb_v_2, v1@sel_1 . v@sel_2 .@sel_2), merge_join(t1@qb_v_2) */ * from v1) t;", - "explain format = 'brief' select * from (select /*+ qb_name(qb_v_2, v1@sel_1 . v@sel_2 .@sel_2), merge_join(t1@qb_v_2), stream_agg(@qb_v_2), qb_name(qb_v_1, v1@sel_1 . v@sel_2 .@sel_1), merge_join(t@qb_v_1) */ * from v1) t;", + "explain format = 'brief' select * from (select /*+ qb_name(qb_v_2, v1.v@sel_2 .@sel_2), merge_join(t1@qb_v_2), stream_agg(@qb_v_2), qb_name(qb_v_1, v1@sel_1 . v@sel_2 .@sel_1), merge_join(t@qb_v_1) */ * from v1) t;", - // TODO: add the warning when the view hints don't set in the first query block - "explain format = 'brief' select /*+ qb_name(qb_v_2, v@sel_1 .@sel_2) */ * from (select /*+ merge_join(t1@qb_v_2) */ * from v) t;", - "explain format = 'brief' select /*+ qb_name(qb_v_2, v@sel_1 .@sel_2), qb_name(qb_v_1, v@sel_1 .@sel1) */ * from (select /*+ merge_join(t1@qb_v_2), stream_agg(@qb_v_2), merge_join(t@qb_v_1) */ * from v) t;", - "explain format = 'brief' select /*+ qb_name(qb_v_2, v1@sel_1 . v@sel_2 .@sel_2) */ * from (select /*+ merge_join(t1@qb_v_2) */ * from v1) t;", - "explain format = 'brief' select /*+ qb_name(qb_v_2, v1@sel_1 . v@sel_2 .@sel_2), qb_name(qb_v_1, v1@sel_1 . v@sel_2 .@sel_1) */ * from (select /*+ merge_join(t1@qb_v_2), stream_agg(@qb_v_2), merge_join(t@qb_v_1) */ * from v1) t;", + "explain format = 'brief' select /*+ qb_name(qb_v_2, v@sel_2 .@sel_2) */ * from (select /*+ merge_join(t1@qb_v_2) */ * from v) t;", + "explain format = 'brief' select /*+ qb_name(qb_v_2, v@sel_2 .@sel_2), qb_name(qb_v_1, v@sel_2 .@sel1) */ * from (select /*+ merge_join(t1@qb_v_2), stream_agg(@qb_v_2), merge_join(t@qb_v_1) */ * from v) t;", + "explain format = 'brief' select /*+ qb_name(qb_v_2, v1@sel_2 . v@sel_2 .@sel_2) */ * from (select /*+ merge_join(t1@qb_v_2) */ * from v1) t;", + "explain format = 'brief' select /*+ qb_name(qb_v_2, v1@sel_2 . v@sel_2 .@sel_2), qb_name(qb_v_1, v1@sel_2 . v@sel_2 .@sel_1) */ * from (select /*+ merge_join(t1@qb_v_2), stream_agg(@qb_v_2), merge_join(t@qb_v_1) */ * from v1) t;", // Define more tables in one view hint - "explain format = 'brief' select /*+ qb_name(qb_v1_2, v2@sel_1 . v1@sel_1 .@sel_2), qb_name(qb_v1_1, v2@sel_1 . v1@sel_1 .@sel_1), merge_join(t1@qb_v1_2, t@qb_v1_1) */ * from v2;", + "explain format = 'brief' select /*+ qb_name(qb_v1_2, v2. v1@sel_2 .@sel_2), qb_name(qb_v1_1, v2@sel_1 . v1@sel_2 .@sel_1), merge_join(t1@qb_v1_2, t@qb_v1_1), merge_join(t1@qb_v1_2) */ * from v2;", "explain format = 'brief' select /*+ qb_name(qb_v_2, v2@sel_1 . v1@sel_2 . v@sel_2 .@sel_2), qb_name(qb_v_1, v2@sel_1 . v1@sel_2 . v@sel_2 .@sel_1), merge_join(t1@qb_v_2, t3@qb_v_2) */ * from v2;", "explain format = 'brief' select /*+ qb_name(qb_v_2, v2@sel_1 . v1@sel_2 . v@sel_2 .@sel_2), qb_name(qb_v_1, v2@sel_1 . v1@sel_2 . v@sel_2 .@sel_1), merge_join(@qb_v_2 t1, t3) */ * from v2;", @@ -721,7 +719,12 @@ // The view contains the hint when creation "explain format = 'brief' select /*+ qb_name(qb_v3_2, v3@sel_1 .@sel_2), merge_join(t1@qb_v3_2) */ * from v3;", - "explain format = 'brief' select /*+ qb_name(qb_v3_2, v3@sel_1 .@sel_2), merge_join(t1@qb_v3_2), hash_agg(@qb_v3_2), qb_name(qb_v3_1, v3@sel_1 .@sel_1), hash_join(t@qb_v3_1) */ * from v3;" + "explain format = 'brief' select /*+ qb_name(qb_v3_2, v3@sel_1 .@sel_2), merge_join(t1@qb_v3_2), hash_agg(@qb_v3_2), qb_name(qb_v3_1, v3@sel_1 .@sel_1), hash_join(t@qb_v3_1) */ * from v3;", + + // The view is in the CTE + "explain with d1 as (\n select a from (\n select a from (\n select /*+ qb_name(qb, v4) use_index(t4@qb, idx_a) */ a from v4 where a < 10\n ) as t0 where a < 9\n ) as t1 where a < 8\n), d2 as (select /*+ qb_name(qb2, v4) use_index(t4@qb2, idx_b) */ a from v4 where b < 10)\n\nselect * from (select * from d1) as t0 join (select * from d2) as t1;", + "explain with d1 as (\n select a from (\n select a from (\n select a from v4 where a < 10\n ) as t0 where a < 9\n ) as t1 where a < 8\n), d2 as (select a from v4 where b < 10)\n\nselect /*+ qb_name(qb, v4@sel_4) use_index(t4@qb, idx_a) qb_name(qb2, v4@sel_5) use_index(t4@qb, idx_b) */ * from (select * from d1) as t0 join (select * from d2) as t1;", + "explain with d1 as (\n select a from (\n select a from (\n select /*+ qb_name(qb, v5) use_index(t4@qb, idx_a) */ a from v4 where a < 10\n ) as t0 where a < 9\n ) as t1 where a < 8\n), d2 as (select /*+ qb_name(qb2, v4) use_index(t4@qb2, idx_b) */ a from v4 where b < 10)\n\nselect * from (select * from d1) as t0 join (select * from d2) as t1;" ] }, { diff --git a/planner/core/testdata/integration_suite_out.json b/planner/core/testdata/integration_suite_out.json index 1ab77ccb7736f..607f6d2947787 100644 --- a/planner/core/testdata/integration_suite_out.json +++ b/planner/core/testdata/integration_suite_out.json @@ -4566,28 +4566,30 @@ "Warn": null }, { - "SQL": "explain format = 'brief' select /*+ qb_name(qb_v1_2, v2@sel_1 . v1@sel_1 .@sel_2), merge_join(t1@qb_v1_2) */ * from v2;", + "SQL": "explain format = 'brief' select /*+ qb_name(qb_v1_2, v2@sel_1 . v1@sel_2 .@sel_2), merge_join(t1@qb_v1_2) */ * from v2;", "Plan": [ "HashJoin 9980.01 root inner join, equal:[eq(test.t.a, Column#24)]", "├─HashAgg(Build) 7984.01 root group by:test.t.a, funcs:count(1)->Column#24", "│ └─HashJoin 12475.01 root inner join, equal:[eq(test.t.a, Column#23)]", "│ ├─HashAgg(Build) 7984.01 root group by:test.t.a, funcs:count(1)->Column#23", - "│ │ └─HashJoin 12475.01 root inner join, equal:[eq(test.t.a, Column#22)]", - "│ │ ├─HashAgg(Build) 7992.00 root group by:test.t2.a, funcs:count(1)->Column#22", - "│ │ │ └─HashJoin 12487.50 root inner join, equal:[eq(test.t1.b, test.t2.b)]", - "│ │ │ ├─TableReader(Build) 9990.00 root data:Selection", - "│ │ │ │ └─Selection 9990.00 cop[tikv] not(isnull(test.t1.b))", - "│ │ │ │ └─TableFullScan 10000.00 cop[tikv] table:t1 keep order:false, stats:pseudo", - "│ │ │ └─TableReader(Probe) 9990.00 root data:Selection", - "│ │ │ └─Selection 9990.00 cop[tikv] not(isnull(test.t2.b))", - "│ │ │ └─TableFullScan 10000.00 cop[tikv] table:t2 keep order:false, stats:pseudo", - "│ │ └─HashJoin(Probe) 12475.01 root inner join, equal:[eq(test.t.b, test.t1.b)]", - "│ │ ├─TableReader(Build) 9990.00 root data:Selection", - "│ │ │ └─Selection 9990.00 cop[tikv] not(isnull(test.t1.b))", - "│ │ │ └─TableFullScan 10000.00 cop[tikv] table:t1 keep order:false, stats:pseudo", - "│ │ └─TableReader(Probe) 9980.01 root data:Selection", - "│ │ └─Selection 9980.01 cop[tikv] not(isnull(test.t.a)), not(isnull(test.t.b))", - "│ │ └─TableFullScan 10000.00 cop[tikv] table:t keep order:false, stats:pseudo", + "│ │ └─MergeJoin 12475.01 root inner join, left key:test.t1.b, right key:test.t.b", + "│ │ ├─Sort(Build) 9980.01 root test.t.b", + "│ │ │ └─HashJoin 9980.01 root inner join, equal:[eq(test.t.a, Column#22)]", + "│ │ │ ├─HashAgg(Build) 7992.00 root group by:test.t2.a, funcs:count(1)->Column#22", + "│ │ │ │ └─HashJoin 12487.50 root inner join, equal:[eq(test.t1.b, test.t2.b)]", + "│ │ │ │ ├─TableReader(Build) 9990.00 root data:Selection", + "│ │ │ │ │ └─Selection 9990.00 cop[tikv] not(isnull(test.t1.b))", + "│ │ │ │ │ └─TableFullScan 10000.00 cop[tikv] table:t1 keep order:false, stats:pseudo", + "│ │ │ │ └─TableReader(Probe) 9990.00 root data:Selection", + "│ │ │ │ └─Selection 9990.00 cop[tikv] not(isnull(test.t2.b))", + "│ │ │ │ └─TableFullScan 10000.00 cop[tikv] table:t2 keep order:false, stats:pseudo", + "│ │ │ └─TableReader(Probe) 9980.01 root data:Selection", + "│ │ │ └─Selection 9980.01 cop[tikv] not(isnull(test.t.a)), not(isnull(test.t.b))", + "│ │ │ └─TableFullScan 10000.00 cop[tikv] table:t keep order:false, stats:pseudo", + "│ │ └─Sort(Probe) 9990.00 root test.t1.b", + "│ │ └─TableReader 9990.00 root data:Selection", + "│ │ └─Selection 9990.00 cop[tikv] not(isnull(test.t1.b))", + "│ │ └─TableFullScan 10000.00 cop[tikv] table:t1 keep order:false, stats:pseudo", "│ └─HashJoin(Probe) 12475.01 root inner join, equal:[eq(test.t.b, test.t1.b)]", "│ ├─TableReader(Build) 9990.00 root data:Selection", "│ │ └─Selection 9990.00 cop[tikv] not(isnull(test.t1.b))", @@ -4602,35 +4604,40 @@ "Warn": null }, { - "SQL": "explain format = 'brief' select /*+ qb_name(qb_v1_2, v2@sel_1 . v1@sel_1 .@sel_2), merge_join(t1@qb_v1_2), stream_agg(@qb_v1_2), qb_name(qb_v1_1, v2@sel_1 . v1@sel_1 .@sel_1), merge_join(t@qb_v1_1) */ * from v2;", + "SQL": "explain format = 'brief' select /*+ qb_name(qb_v1_2, v2@sel_1 . v1@sel_2 .@sel_2), merge_join(t1@qb_v1_2), stream_agg(@qb_v1_2), qb_name(qb_v1_1, v2@sel_1 . v1@sel_2 .@sel_1), merge_join(t@qb_v1_1) */ * from v2;", "Plan": [ "HashJoin 9980.01 root inner join, equal:[eq(test.t.a, Column#24)]", "├─HashAgg(Build) 7984.01 root group by:test.t.a, funcs:count(1)->Column#24", - "│ └─HashJoin 12475.01 root inner join, equal:[eq(test.t.a, Column#23)]", - "│ ├─HashAgg(Build) 7984.01 root group by:test.t.a, funcs:count(1)->Column#23", - "│ │ └─HashJoin 12475.01 root inner join, equal:[eq(test.t.a, Column#22)]", - "│ │ ├─HashAgg(Build) 7992.00 root group by:test.t2.a, funcs:count(1)->Column#22", - "│ │ │ └─HashJoin 12487.50 root inner join, equal:[eq(test.t1.b, test.t2.b)]", - "│ │ │ ├─TableReader(Build) 9990.00 root data:Selection", - "│ │ │ │ └─Selection 9990.00 cop[tikv] not(isnull(test.t1.b))", - "│ │ │ │ └─TableFullScan 10000.00 cop[tikv] table:t1 keep order:false, stats:pseudo", - "│ │ │ └─TableReader(Probe) 9990.00 root data:Selection", - "│ │ │ └─Selection 9990.00 cop[tikv] not(isnull(test.t2.b))", - "│ │ │ └─TableFullScan 10000.00 cop[tikv] table:t2 keep order:false, stats:pseudo", - "│ │ └─HashJoin(Probe) 12475.01 root inner join, equal:[eq(test.t.b, test.t1.b)]", - "│ │ ├─TableReader(Build) 9990.00 root data:Selection", - "│ │ │ └─Selection 9990.00 cop[tikv] not(isnull(test.t1.b))", - "│ │ │ └─TableFullScan 10000.00 cop[tikv] table:t1 keep order:false, stats:pseudo", - "│ │ └─TableReader(Probe) 9980.01 root data:Selection", - "│ │ └─Selection 9980.01 cop[tikv] not(isnull(test.t.a)), not(isnull(test.t.b))", - "│ │ └─TableFullScan 10000.00 cop[tikv] table:t keep order:false, stats:pseudo", - "│ └─HashJoin(Probe) 12475.01 root inner join, equal:[eq(test.t.b, test.t1.b)]", - "│ ├─TableReader(Build) 9990.00 root data:Selection", - "│ │ └─Selection 9990.00 cop[tikv] not(isnull(test.t1.b))", - "│ │ └─TableFullScan 10000.00 cop[tikv] table:t1 keep order:false, stats:pseudo", - "│ └─TableReader(Probe) 9980.01 root data:Selection", - "│ └─Selection 9980.01 cop[tikv] not(isnull(test.t.a)), not(isnull(test.t.b))", - "│ └─TableFullScan 10000.00 cop[tikv] table:t keep order:false, stats:pseudo", + "│ └─HashJoin 12475.01 root inner join, equal:[eq(test.t1.b, test.t.b)]", + "│ ├─MergeJoin(Build) 9980.01 root inner join, left key:test.t.a, right key:Column#23", + "│ │ ├─Sort(Build) 7984.01 root Column#23", + "│ │ │ └─StreamAgg 7984.01 root group by:test.t.a, funcs:count(1)->Column#23", + "│ │ │ └─Sort 12475.01 root test.t.a", + "│ │ │ └─MergeJoin 12475.01 root inner join, left key:test.t1.b, right key:test.t.b", + "│ │ │ ├─Sort(Build) 9980.01 root test.t.b", + "│ │ │ │ └─HashJoin 9980.01 root inner join, equal:[eq(test.t.a, Column#22)]", + "│ │ │ │ ├─HashAgg(Build) 7992.00 root group by:test.t2.a, funcs:count(1)->Column#22", + "│ │ │ │ │ └─HashJoin 12487.50 root inner join, equal:[eq(test.t1.b, test.t2.b)]", + "│ │ │ │ │ ├─TableReader(Build) 9990.00 root data:Selection", + "│ │ │ │ │ │ └─Selection 9990.00 cop[tikv] not(isnull(test.t1.b))", + "│ │ │ │ │ │ └─TableFullScan 10000.00 cop[tikv] table:t1 keep order:false, stats:pseudo", + "│ │ │ │ │ └─TableReader(Probe) 9990.00 root data:Selection", + "│ │ │ │ │ └─Selection 9990.00 cop[tikv] not(isnull(test.t2.b))", + "│ │ │ │ │ └─TableFullScan 10000.00 cop[tikv] table:t2 keep order:false, stats:pseudo", + "│ │ │ │ └─TableReader(Probe) 9980.01 root data:Selection", + "│ │ │ │ └─Selection 9980.01 cop[tikv] not(isnull(test.t.a)), not(isnull(test.t.b))", + "│ │ │ │ └─TableFullScan 10000.00 cop[tikv] table:t keep order:false, stats:pseudo", + "│ │ │ └─Sort(Probe) 9990.00 root test.t1.b", + "│ │ │ └─TableReader 9990.00 root data:Selection", + "│ │ │ └─Selection 9990.00 cop[tikv] not(isnull(test.t1.b))", + "│ │ │ └─TableFullScan 10000.00 cop[tikv] table:t1 keep order:false, stats:pseudo", + "│ │ └─Sort(Probe) 9980.01 root test.t.a", + "│ │ └─TableReader 9980.01 root data:Selection", + "│ │ └─Selection 9980.01 cop[tikv] not(isnull(test.t.a)), not(isnull(test.t.b))", + "│ │ └─TableFullScan 10000.00 cop[tikv] table:t keep order:false, stats:pseudo", + "│ └─TableReader(Probe) 9990.00 root data:Selection", + "│ └─Selection 9990.00 cop[tikv] not(isnull(test.t1.b))", + "│ └─TableFullScan 10000.00 cop[tikv] table:t1 keep order:false, stats:pseudo", "└─TableReader(Probe) 9990.00 root data:Selection", " └─Selection 9990.00 cop[tikv] not(isnull(test.t.a))", " └─TableFullScan 10000.00 cop[tikv] table:t keep order:false, stats:pseudo" @@ -4855,7 +4862,9 @@ " └─Selection 9990.00 cop[tikv] not(isnull(test.t.a))", " └─TableFullScan 10000.00 cop[tikv] table:t keep order:false, stats:pseudo" ], - "Warn": null + "Warn": [ + "The qb_name hint qb_v1_2 is unused, please check whether the table list in the qb_name hint qb_v1_2 is correct" + ] }, { "SQL": "explain format = 'brief' select /*+ qb_name(qb_v1_2, v2@sel_1 . v@sel_1 .@sel_2), merge_join(t1@qb_v1_2) */ * from v2;", @@ -4895,7 +4904,9 @@ " └─Selection 9990.00 cop[tikv] not(isnull(test.t.a))", " └─TableFullScan 10000.00 cop[tikv] table:t keep order:false, stats:pseudo" ], - "Warn": null + "Warn": [ + "The qb_name hint qb_v1_2 is unused, please check whether the table list in the qb_name hint qb_v1_2 is correct" + ] }, { "SQL": "explain format = 'brief' select /*+ qb_name(qb_v2_2, vv@sel_1 .@sel_2), merge_join(t1@qb_v2_2) */ * from v2 vv;", @@ -4977,7 +4988,9 @@ " └─Selection 9990.00 cop[tikv] not(isnull(test.t.a))", " └─TableFullScan 10000.00 cop[tikv] table:t keep order:false, stats:pseudo" ], - "Warn": null + "Warn": [ + "The qb_name hint qb_v2_2 is unused, please check whether the table list in the qb_name hint qb_v2_2 is correct" + ] }, { "SQL": "explain format = 'brief' select * from (select /*+ qb_name(qb_v_2, v@sel_1 .@sel_2), merge_join(t1@qb_v_2) */ * from v) t;", @@ -5000,36 +5013,34 @@ " └─TableFullScan 10000.00 cop[tikv] table:t keep order:false, stats:pseudo" ], "Warn": [ - "The qb_name hint for view only supports to be defined in the first query block", - "Hint merge_join(`t1`@`qb_v_2`) is ignored due to unknown query block name" + "The qb_name hint qb_v_2 is unused, please check whether the table list in the qb_name hint qb_v_2 is correct" ] }, { - "SQL": "explain format = 'brief' select * from (select /*+ qb_name(qb_v_2, v@sel_1 .@sel_2), merge_join(t1@qb_v_2), stream_agg(@qb_v_2), qb_name(qb_v_1, v@sel_1 .@sel1), merge_join(t@qb_v_1) */ * from v) t;", + "SQL": "explain format = 'brief' select * from (select /*+ qb_name(qb_v_2, v.@sel_2), merge_join(t1@qb_v_2), stream_agg(@qb_v_2), qb_name(qb_v_1, v@sel_1 .@sel1), merge_join(t@qb_v_1) */ * from v) t;", "Plan": [ "HashJoin 9980.01 root inner join, equal:[eq(test.t.a, Column#13)]", - "├─HashAgg(Build) 7984.01 root group by:test.t2.a, funcs:count(1)->Column#13", - "│ └─HashJoin 15593.77 root inner join, equal:[eq(test.t2.a, test.t3.a)]", - "│ ├─TableReader(Build) 9990.00 root data:Selection", - "│ │ └─Selection 9990.00 cop[tikv] not(isnull(test.t3.a))", - "│ │ └─TableFullScan 10000.00 cop[tikv] table:t3 keep order:false, stats:pseudo", - "│ └─HashJoin(Probe) 12475.01 root inner join, equal:[eq(test.t2.b, test.t1.b)]", + "├─StreamAgg(Build) 7984.01 root group by:test.t2.a, funcs:count(1)->Column#13", + "│ └─Sort 15593.77 root test.t2.a", + "│ └─HashJoin 15593.77 root inner join, equal:[eq(test.t3.a, test.t2.a)]", "│ ├─TableReader(Build) 9990.00 root data:Selection", - "│ │ └─Selection 9990.00 cop[tikv] not(isnull(test.t1.b))", - "│ │ └─TableFullScan 10000.00 cop[tikv] table:t1 keep order:false, stats:pseudo", - "│ └─TableReader(Probe) 9980.01 root data:Selection", - "│ └─Selection 9980.01 cop[tikv] not(isnull(test.t2.a)), not(isnull(test.t2.b))", - "│ └─TableFullScan 10000.00 cop[tikv] table:t2 keep order:false, stats:pseudo", + "│ │ └─Selection 9990.00 cop[tikv] not(isnull(test.t3.a))", + "│ │ └─TableFullScan 10000.00 cop[tikv] table:t3 keep order:false, stats:pseudo", + "│ └─MergeJoin(Probe) 12475.01 root inner join, left key:test.t1.b, right key:test.t2.b", + "│ ├─Sort(Build) 9980.01 root test.t2.b", + "│ │ └─TableReader 9980.01 root data:Selection", + "│ │ └─Selection 9980.01 cop[tikv] not(isnull(test.t2.a)), not(isnull(test.t2.b))", + "│ │ └─TableFullScan 10000.00 cop[tikv] table:t2 keep order:false, stats:pseudo", + "│ └─Sort(Probe) 9990.00 root test.t1.b", + "│ └─TableReader 9990.00 root data:Selection", + "│ └─Selection 9990.00 cop[tikv] not(isnull(test.t1.b))", + "│ └─TableFullScan 10000.00 cop[tikv] table:t1 keep order:false, stats:pseudo", "└─TableReader(Probe) 9990.00 root data:Selection", " └─Selection 9990.00 cop[tikv] not(isnull(test.t.a))", " └─TableFullScan 10000.00 cop[tikv] table:t keep order:false, stats:pseudo" ], "Warn": [ - "The qb_name hint for view only supports to be defined in the first query block", - "The qb_name hint for view only supports to be defined in the first query block", - "Hint merge_join(`t1`@`qb_v_2`) is ignored due to unknown query block name", - "Hint stream_agg(@`qb_v_2`) is ignored due to unknown query block name", - "Hint merge_join(`t`@`qb_v_1`) is ignored due to unknown query block name" + "The qb_name hint qb_v_1 is unused, please check whether the table list in the qb_name hint qb_v_1 is correct" ] }, { @@ -5062,28 +5073,30 @@ " └─TableFullScan 10000.00 cop[tikv] table:t keep order:false, stats:pseudo" ], "Warn": [ - "The qb_name hint for view only supports to be defined in the first query block", - "Hint merge_join(`t1`@`qb_v_2`) is ignored due to unknown query block name" + "The qb_name hint qb_v_2 is unused, please check whether the table list in the qb_name hint qb_v_2 is correct" ] }, { - "SQL": "explain format = 'brief' select * from (select /*+ qb_name(qb_v_2, v1@sel_1 . v@sel_2 .@sel_2), merge_join(t1@qb_v_2), stream_agg(@qb_v_2), qb_name(qb_v_1, v1@sel_1 . v@sel_2 .@sel_1), merge_join(t@qb_v_1) */ * from v1) t;", + "SQL": "explain format = 'brief' select * from (select /*+ qb_name(qb_v_2, v1.v@sel_2 .@sel_2), merge_join(t1@qb_v_2), stream_agg(@qb_v_2), qb_name(qb_v_1, v1@sel_1 . v@sel_2 .@sel_1), merge_join(t@qb_v_1) */ * from v1) t;", "Plan": [ "HashJoin 9980.01 root inner join, equal:[eq(test.t.a, Column#20)]", "├─HashAgg(Build) 7984.01 root group by:test.t.a, funcs:count(1)->Column#20", "│ └─HashJoin 12475.01 root inner join, equal:[eq(test.t.a, Column#19)]", - "│ ├─HashAgg(Build) 7984.01 root group by:test.t2.a, funcs:count(1)->Column#19", - "│ │ └─HashJoin 15593.77 root inner join, equal:[eq(test.t2.a, test.t3.a)]", - "│ │ ├─TableReader(Build) 9990.00 root data:Selection", - "│ │ │ └─Selection 9990.00 cop[tikv] not(isnull(test.t3.a))", - "│ │ │ └─TableFullScan 10000.00 cop[tikv] table:t3 keep order:false, stats:pseudo", - "│ │ └─HashJoin(Probe) 12475.01 root inner join, equal:[eq(test.t2.b, test.t1.b)]", + "│ ├─StreamAgg(Build) 7984.01 root group by:test.t2.a, funcs:count(1)->Column#19", + "│ │ └─Sort 15593.77 root test.t2.a", + "│ │ └─HashJoin 15593.77 root inner join, equal:[eq(test.t3.a, test.t2.a)]", "│ │ ├─TableReader(Build) 9990.00 root data:Selection", - "│ │ │ └─Selection 9990.00 cop[tikv] not(isnull(test.t1.b))", - "│ │ │ └─TableFullScan 10000.00 cop[tikv] table:t1 keep order:false, stats:pseudo", - "│ │ └─TableReader(Probe) 9980.01 root data:Selection", - "│ │ └─Selection 9980.01 cop[tikv] not(isnull(test.t2.a)), not(isnull(test.t2.b))", - "│ │ └─TableFullScan 10000.00 cop[tikv] table:t2 keep order:false, stats:pseudo", + "│ │ │ └─Selection 9990.00 cop[tikv] not(isnull(test.t3.a))", + "│ │ │ └─TableFullScan 10000.00 cop[tikv] table:t3 keep order:false, stats:pseudo", + "│ │ └─MergeJoin(Probe) 12475.01 root inner join, left key:test.t1.b, right key:test.t2.b", + "│ │ ├─Sort(Build) 9980.01 root test.t2.b", + "│ │ │ └─TableReader 9980.01 root data:Selection", + "│ │ │ └─Selection 9980.01 cop[tikv] not(isnull(test.t2.a)), not(isnull(test.t2.b))", + "│ │ │ └─TableFullScan 10000.00 cop[tikv] table:t2 keep order:false, stats:pseudo", + "│ │ └─Sort(Probe) 9990.00 root test.t1.b", + "│ │ └─TableReader 9990.00 root data:Selection", + "│ │ └─Selection 9990.00 cop[tikv] not(isnull(test.t1.b))", + "│ │ └─TableFullScan 10000.00 cop[tikv] table:t1 keep order:false, stats:pseudo", "│ └─HashJoin(Probe) 12475.01 root inner join, equal:[eq(test.t.b, test.t1.b)]", "│ ├─TableReader(Build) 9990.00 root data:Selection", "│ │ └─Selection 9990.00 cop[tikv] not(isnull(test.t1.b))", @@ -5096,81 +5109,80 @@ " └─TableFullScan 10000.00 cop[tikv] table:t keep order:false, stats:pseudo" ], "Warn": [ - "The qb_name hint for view only supports to be defined in the first query block", - "The qb_name hint for view only supports to be defined in the first query block", - "Hint merge_join(`t1`@`qb_v_2`) is ignored due to unknown query block name", - "Hint stream_agg(@`qb_v_2`) is ignored due to unknown query block name", - "Hint merge_join(`t`@`qb_v_1`) is ignored due to unknown query block name" + "The qb_name hint qb_v_1 is unused, please check whether the table list in the qb_name hint qb_v_1 is correct" ] }, { - "SQL": "explain format = 'brief' select /*+ qb_name(qb_v_2, v@sel_1 .@sel_2) */ * from (select /*+ merge_join(t1@qb_v_2) */ * from v) t;", + "SQL": "explain format = 'brief' select /*+ qb_name(qb_v_2, v@sel_2 .@sel_2) */ * from (select /*+ merge_join(t1@qb_v_2) */ * from v) t;", "Plan": [ "HashJoin 9980.01 root inner join, equal:[eq(test.t.a, Column#13)]", "├─HashAgg(Build) 7984.01 root group by:test.t2.a, funcs:count(1)->Column#13", - "│ └─HashJoin 15593.77 root inner join, equal:[eq(test.t2.a, test.t3.a)]", + "│ └─HashJoin 15593.77 root inner join, equal:[eq(test.t3.a, test.t2.a)]", "│ ├─TableReader(Build) 9990.00 root data:Selection", "│ │ └─Selection 9990.00 cop[tikv] not(isnull(test.t3.a))", "│ │ └─TableFullScan 10000.00 cop[tikv] table:t3 keep order:false, stats:pseudo", - "│ └─HashJoin(Probe) 12475.01 root inner join, equal:[eq(test.t2.b, test.t1.b)]", - "│ ├─TableReader(Build) 9990.00 root data:Selection", - "│ │ └─Selection 9990.00 cop[tikv] not(isnull(test.t1.b))", - "│ │ └─TableFullScan 10000.00 cop[tikv] table:t1 keep order:false, stats:pseudo", - "│ └─TableReader(Probe) 9980.01 root data:Selection", - "│ └─Selection 9980.01 cop[tikv] not(isnull(test.t2.a)), not(isnull(test.t2.b))", - "│ └─TableFullScan 10000.00 cop[tikv] table:t2 keep order:false, stats:pseudo", + "│ └─MergeJoin(Probe) 12475.01 root inner join, left key:test.t1.b, right key:test.t2.b", + "│ ├─Sort(Build) 9980.01 root test.t2.b", + "│ │ └─TableReader 9980.01 root data:Selection", + "│ │ └─Selection 9980.01 cop[tikv] not(isnull(test.t2.a)), not(isnull(test.t2.b))", + "│ │ └─TableFullScan 10000.00 cop[tikv] table:t2 keep order:false, stats:pseudo", + "│ └─Sort(Probe) 9990.00 root test.t1.b", + "│ └─TableReader 9990.00 root data:Selection", + "│ └─Selection 9990.00 cop[tikv] not(isnull(test.t1.b))", + "│ └─TableFullScan 10000.00 cop[tikv] table:t1 keep order:false, stats:pseudo", "└─TableReader(Probe) 9990.00 root data:Selection", " └─Selection 9990.00 cop[tikv] not(isnull(test.t.a))", " └─TableFullScan 10000.00 cop[tikv] table:t keep order:false, stats:pseudo" ], - "Warn": [ - "Hint merge_join(`t1`@`qb_v_2`) is ignored due to unknown query block name" - ] + "Warn": null }, { - "SQL": "explain format = 'brief' select /*+ qb_name(qb_v_2, v@sel_1 .@sel_2), qb_name(qb_v_1, v@sel_1 .@sel1) */ * from (select /*+ merge_join(t1@qb_v_2), stream_agg(@qb_v_2), merge_join(t@qb_v_1) */ * from v) t;", + "SQL": "explain format = 'brief' select /*+ qb_name(qb_v_2, v@sel_2 .@sel_2), qb_name(qb_v_1, v@sel_2 .@sel1) */ * from (select /*+ merge_join(t1@qb_v_2), stream_agg(@qb_v_2), merge_join(t@qb_v_1) */ * from v) t;", "Plan": [ "HashJoin 9980.01 root inner join, equal:[eq(test.t.a, Column#13)]", - "├─HashAgg(Build) 7984.01 root group by:test.t2.a, funcs:count(1)->Column#13", - "│ └─HashJoin 15593.77 root inner join, equal:[eq(test.t2.a, test.t3.a)]", - "│ ├─TableReader(Build) 9990.00 root data:Selection", - "│ │ └─Selection 9990.00 cop[tikv] not(isnull(test.t3.a))", - "│ │ └─TableFullScan 10000.00 cop[tikv] table:t3 keep order:false, stats:pseudo", - "│ └─HashJoin(Probe) 12475.01 root inner join, equal:[eq(test.t2.b, test.t1.b)]", + "├─StreamAgg(Build) 7984.01 root group by:test.t2.a, funcs:count(1)->Column#13", + "│ └─Sort 15593.77 root test.t2.a", + "│ └─HashJoin 15593.77 root inner join, equal:[eq(test.t3.a, test.t2.a)]", "│ ├─TableReader(Build) 9990.00 root data:Selection", - "│ │ └─Selection 9990.00 cop[tikv] not(isnull(test.t1.b))", - "│ │ └─TableFullScan 10000.00 cop[tikv] table:t1 keep order:false, stats:pseudo", - "│ └─TableReader(Probe) 9980.01 root data:Selection", - "│ └─Selection 9980.01 cop[tikv] not(isnull(test.t2.a)), not(isnull(test.t2.b))", - "│ └─TableFullScan 10000.00 cop[tikv] table:t2 keep order:false, stats:pseudo", + "│ │ └─Selection 9990.00 cop[tikv] not(isnull(test.t3.a))", + "│ │ └─TableFullScan 10000.00 cop[tikv] table:t3 keep order:false, stats:pseudo", + "│ └─MergeJoin(Probe) 12475.01 root inner join, left key:test.t1.b, right key:test.t2.b", + "│ ├─Sort(Build) 9980.01 root test.t2.b", + "│ │ └─TableReader 9980.01 root data:Selection", + "│ │ └─Selection 9980.01 cop[tikv] not(isnull(test.t2.a)), not(isnull(test.t2.b))", + "│ │ └─TableFullScan 10000.00 cop[tikv] table:t2 keep order:false, stats:pseudo", + "│ └─Sort(Probe) 9990.00 root test.t1.b", + "│ └─TableReader 9990.00 root data:Selection", + "│ └─Selection 9990.00 cop[tikv] not(isnull(test.t1.b))", + "│ └─TableFullScan 10000.00 cop[tikv] table:t1 keep order:false, stats:pseudo", "└─TableReader(Probe) 9990.00 root data:Selection", " └─Selection 9990.00 cop[tikv] not(isnull(test.t.a))", " └─TableFullScan 10000.00 cop[tikv] table:t keep order:false, stats:pseudo" ], "Warn": [ - "Hint merge_join(`t1`@`qb_v_2`) is ignored due to unknown query block name", - "Hint stream_agg(@`qb_v_2`) is ignored due to unknown query block name", - "Hint merge_join(`t`@`qb_v_1`) is ignored due to unknown query block name" + "The qb_name hint qb_v_1 is unused, please check whether the table list in the qb_name hint qb_v_1 is correct" ] }, { - "SQL": "explain format = 'brief' select /*+ qb_name(qb_v_2, v1@sel_1 . v@sel_2 .@sel_2) */ * from (select /*+ merge_join(t1@qb_v_2) */ * from v1) t;", + "SQL": "explain format = 'brief' select /*+ qb_name(qb_v_2, v1@sel_2 . v@sel_2 .@sel_2) */ * from (select /*+ merge_join(t1@qb_v_2) */ * from v1) t;", "Plan": [ "HashJoin 9980.01 root inner join, equal:[eq(test.t.a, Column#20)]", "├─HashAgg(Build) 7984.01 root group by:test.t.a, funcs:count(1)->Column#20", "│ └─HashJoin 12475.01 root inner join, equal:[eq(test.t.a, Column#19)]", "│ ├─HashAgg(Build) 7984.01 root group by:test.t2.a, funcs:count(1)->Column#19", - "│ │ └─HashJoin 15593.77 root inner join, equal:[eq(test.t2.a, test.t3.a)]", + "│ │ └─HashJoin 15593.77 root inner join, equal:[eq(test.t3.a, test.t2.a)]", "│ │ ├─TableReader(Build) 9990.00 root data:Selection", "│ │ │ └─Selection 9990.00 cop[tikv] not(isnull(test.t3.a))", "│ │ │ └─TableFullScan 10000.00 cop[tikv] table:t3 keep order:false, stats:pseudo", - "│ │ └─HashJoin(Probe) 12475.01 root inner join, equal:[eq(test.t2.b, test.t1.b)]", - "│ │ ├─TableReader(Build) 9990.00 root data:Selection", - "│ │ │ └─Selection 9990.00 cop[tikv] not(isnull(test.t1.b))", - "│ │ │ └─TableFullScan 10000.00 cop[tikv] table:t1 keep order:false, stats:pseudo", - "│ │ └─TableReader(Probe) 9980.01 root data:Selection", - "│ │ └─Selection 9980.01 cop[tikv] not(isnull(test.t2.a)), not(isnull(test.t2.b))", - "│ │ └─TableFullScan 10000.00 cop[tikv] table:t2 keep order:false, stats:pseudo", + "│ │ └─MergeJoin(Probe) 12475.01 root inner join, left key:test.t1.b, right key:test.t2.b", + "│ │ ├─Sort(Build) 9980.01 root test.t2.b", + "│ │ │ └─TableReader 9980.01 root data:Selection", + "│ │ │ └─Selection 9980.01 cop[tikv] not(isnull(test.t2.a)), not(isnull(test.t2.b))", + "│ │ │ └─TableFullScan 10000.00 cop[tikv] table:t2 keep order:false, stats:pseudo", + "│ │ └─Sort(Probe) 9990.00 root test.t1.b", + "│ │ └─TableReader 9990.00 root data:Selection", + "│ │ └─Selection 9990.00 cop[tikv] not(isnull(test.t1.b))", + "│ │ └─TableFullScan 10000.00 cop[tikv] table:t1 keep order:false, stats:pseudo", "│ └─HashJoin(Probe) 12475.01 root inner join, equal:[eq(test.t.b, test.t1.b)]", "│ ├─TableReader(Build) 9990.00 root data:Selection", "│ │ └─Selection 9990.00 cop[tikv] not(isnull(test.t1.b))", @@ -5182,72 +5194,73 @@ " └─Selection 9990.00 cop[tikv] not(isnull(test.t.a))", " └─TableFullScan 10000.00 cop[tikv] table:t keep order:false, stats:pseudo" ], - "Warn": [ - "Hint merge_join(`t1`@`qb_v_2`) is ignored due to unknown query block name" - ] + "Warn": null }, { - "SQL": "explain format = 'brief' select /*+ qb_name(qb_v_2, v1@sel_1 . v@sel_2 .@sel_2), qb_name(qb_v_1, v1@sel_1 . v@sel_2 .@sel_1) */ * from (select /*+ merge_join(t1@qb_v_2), stream_agg(@qb_v_2), merge_join(t@qb_v_1) */ * from v1) t;", + "SQL": "explain format = 'brief' select /*+ qb_name(qb_v_2, v1@sel_2 . v@sel_2 .@sel_2), qb_name(qb_v_1, v1@sel_2 . v@sel_2 .@sel_1) */ * from (select /*+ merge_join(t1@qb_v_2), stream_agg(@qb_v_2), merge_join(t@qb_v_1) */ * from v1) t;", "Plan": [ "HashJoin 9980.01 root inner join, equal:[eq(test.t.a, Column#20)]", "├─HashAgg(Build) 7984.01 root group by:test.t.a, funcs:count(1)->Column#20", - "│ └─HashJoin 12475.01 root inner join, equal:[eq(test.t.a, Column#19)]", - "│ ├─HashAgg(Build) 7984.01 root group by:test.t2.a, funcs:count(1)->Column#19", - "│ │ └─HashJoin 15593.77 root inner join, equal:[eq(test.t2.a, test.t3.a)]", - "│ │ ├─TableReader(Build) 9990.00 root data:Selection", - "│ │ │ └─Selection 9990.00 cop[tikv] not(isnull(test.t3.a))", - "│ │ │ └─TableFullScan 10000.00 cop[tikv] table:t3 keep order:false, stats:pseudo", - "│ │ └─HashJoin(Probe) 12475.01 root inner join, equal:[eq(test.t2.b, test.t1.b)]", - "│ │ ├─TableReader(Build) 9990.00 root data:Selection", - "│ │ │ └─Selection 9990.00 cop[tikv] not(isnull(test.t1.b))", - "│ │ │ └─TableFullScan 10000.00 cop[tikv] table:t1 keep order:false, stats:pseudo", - "│ │ └─TableReader(Probe) 9980.01 root data:Selection", - "│ │ └─Selection 9980.01 cop[tikv] not(isnull(test.t2.a)), not(isnull(test.t2.b))", - "│ │ └─TableFullScan 10000.00 cop[tikv] table:t2 keep order:false, stats:pseudo", - "│ └─HashJoin(Probe) 12475.01 root inner join, equal:[eq(test.t.b, test.t1.b)]", - "│ ├─TableReader(Build) 9990.00 root data:Selection", - "│ │ └─Selection 9990.00 cop[tikv] not(isnull(test.t1.b))", - "│ │ └─TableFullScan 10000.00 cop[tikv] table:t1 keep order:false, stats:pseudo", - "│ └─TableReader(Probe) 9980.01 root data:Selection", - "│ └─Selection 9980.01 cop[tikv] not(isnull(test.t.a)), not(isnull(test.t.b))", - "│ └─TableFullScan 10000.00 cop[tikv] table:t keep order:false, stats:pseudo", + "│ └─HashJoin 12475.01 root inner join, equal:[eq(test.t1.b, test.t.b)]", + "│ ├─MergeJoin(Build) 9980.01 root inner join, left key:test.t.a, right key:Column#19", + "│ │ ├─Sort(Build) 7984.01 root Column#19", + "│ │ │ └─StreamAgg 7984.01 root group by:test.t2.a, funcs:count(1)->Column#19", + "│ │ │ └─Sort 15593.77 root test.t2.a", + "│ │ │ └─HashJoin 15593.77 root inner join, equal:[eq(test.t3.a, test.t2.a)]", + "│ │ │ ├─TableReader(Build) 9990.00 root data:Selection", + "│ │ │ │ └─Selection 9990.00 cop[tikv] not(isnull(test.t3.a))", + "│ │ │ │ └─TableFullScan 10000.00 cop[tikv] table:t3 keep order:false, stats:pseudo", + "│ │ │ └─MergeJoin(Probe) 12475.01 root inner join, left key:test.t1.b, right key:test.t2.b", + "│ │ │ ├─Sort(Build) 9980.01 root test.t2.b", + "│ │ │ │ └─TableReader 9980.01 root data:Selection", + "│ │ │ │ └─Selection 9980.01 cop[tikv] not(isnull(test.t2.a)), not(isnull(test.t2.b))", + "│ │ │ │ └─TableFullScan 10000.00 cop[tikv] table:t2 keep order:false, stats:pseudo", + "│ │ │ └─Sort(Probe) 9990.00 root test.t1.b", + "│ │ │ └─TableReader 9990.00 root data:Selection", + "│ │ │ └─Selection 9990.00 cop[tikv] not(isnull(test.t1.b))", + "│ │ │ └─TableFullScan 10000.00 cop[tikv] table:t1 keep order:false, stats:pseudo", + "│ │ └─Sort(Probe) 9980.01 root test.t.a", + "│ │ └─TableReader 9980.01 root data:Selection", + "│ │ └─Selection 9980.01 cop[tikv] not(isnull(test.t.a)), not(isnull(test.t.b))", + "│ │ └─TableFullScan 10000.00 cop[tikv] table:t keep order:false, stats:pseudo", + "│ └─TableReader(Probe) 9990.00 root data:Selection", + "│ └─Selection 9990.00 cop[tikv] not(isnull(test.t1.b))", + "│ └─TableFullScan 10000.00 cop[tikv] table:t1 keep order:false, stats:pseudo", "└─TableReader(Probe) 9990.00 root data:Selection", " └─Selection 9990.00 cop[tikv] not(isnull(test.t.a))", " └─TableFullScan 10000.00 cop[tikv] table:t keep order:false, stats:pseudo" ], - "Warn": [ - "Hint merge_join(`t1`@`qb_v_2`) is ignored due to unknown query block name", - "Hint stream_agg(@`qb_v_2`) is ignored due to unknown query block name", - "Hint merge_join(`t`@`qb_v_1`) is ignored due to unknown query block name" - ] + "Warn": null }, { - "SQL": "explain format = 'brief' select /*+ qb_name(qb_v1_2, v2@sel_1 . v1@sel_1 .@sel_2), qb_name(qb_v1_1, v2@sel_1 . v1@sel_1 .@sel_1), merge_join(t1@qb_v1_2, t@qb_v1_1) */ * from v2;", + "SQL": "explain format = 'brief' select /*+ qb_name(qb_v1_2, v2. v1@sel_2 .@sel_2), qb_name(qb_v1_1, v2@sel_1 . v1@sel_2 .@sel_1), merge_join(t1@qb_v1_2, t@qb_v1_1), merge_join(t1@qb_v1_2) */ * from v2;", "Plan": [ "HashJoin 9980.01 root inner join, equal:[eq(test.t.a, Column#27)]", "├─HashAgg(Build) 7984.01 root group by:test.t.a, funcs:count(1)->Column#27", "│ └─HashJoin 12475.01 root inner join, equal:[eq(test.t.a, Column#26)]", "│ ├─HashAgg(Build) 7984.01 root group by:test.t.a, funcs:count(1)->Column#26", - "│ │ └─HashJoin 12475.01 root inner join, equal:[eq(test.t.a, Column#25)]", - "│ │ ├─HashAgg(Build) 7984.01 root group by:test.t2.a, funcs:count(1)->Column#25", - "│ │ │ └─HashJoin 15593.77 root inner join, equal:[eq(test.t2.a, test.t3.a)]", - "│ │ │ ├─TableReader(Build) 9990.00 root data:Selection", - "│ │ │ │ └─Selection 9990.00 cop[tikv] not(isnull(test.t3.a))", - "│ │ │ │ └─TableFullScan 10000.00 cop[tikv] table:t3 keep order:false, stats:pseudo", - "│ │ │ └─HashJoin(Probe) 12475.01 root inner join, equal:[eq(test.t2.b, test.t1.b)]", - "│ │ │ ├─TableReader(Build) 9990.00 root data:Selection", - "│ │ │ │ └─Selection 9990.00 cop[tikv] not(isnull(test.t1.b))", - "│ │ │ │ └─TableFullScan 10000.00 cop[tikv] table:t1 keep order:false, stats:pseudo", - "│ │ │ └─TableReader(Probe) 9980.01 root data:Selection", - "│ │ │ └─Selection 9980.01 cop[tikv] not(isnull(test.t2.a)), not(isnull(test.t2.b))", - "│ │ │ └─TableFullScan 10000.00 cop[tikv] table:t2 keep order:false, stats:pseudo", - "│ │ └─HashJoin(Probe) 12475.01 root inner join, equal:[eq(test.t.b, test.t1.b)]", - "│ │ ├─TableReader(Build) 9990.00 root data:Selection", - "│ │ │ └─Selection 9990.00 cop[tikv] not(isnull(test.t1.b))", - "│ │ │ └─TableFullScan 10000.00 cop[tikv] table:t1 keep order:false, stats:pseudo", - "│ │ └─TableReader(Probe) 9980.01 root data:Selection", - "│ │ └─Selection 9980.01 cop[tikv] not(isnull(test.t.a)), not(isnull(test.t.b))", - "│ │ └─TableFullScan 10000.00 cop[tikv] table:t keep order:false, stats:pseudo", + "│ │ └─MergeJoin 12475.01 root inner join, left key:test.t1.b, right key:test.t.b", + "│ │ ├─Sort(Build) 9980.01 root test.t.b", + "│ │ │ └─HashJoin 9980.01 root inner join, equal:[eq(test.t.a, Column#25)]", + "│ │ │ ├─HashAgg(Build) 7984.01 root group by:test.t2.a, funcs:count(1)->Column#25", + "│ │ │ │ └─HashJoin 15593.77 root inner join, equal:[eq(test.t2.a, test.t3.a)]", + "│ │ │ │ ├─TableReader(Build) 9990.00 root data:Selection", + "│ │ │ │ │ └─Selection 9990.00 cop[tikv] not(isnull(test.t3.a))", + "│ │ │ │ │ └─TableFullScan 10000.00 cop[tikv] table:t3 keep order:false, stats:pseudo", + "│ │ │ │ └─HashJoin(Probe) 12475.01 root inner join, equal:[eq(test.t2.b, test.t1.b)]", + "│ │ │ │ ├─TableReader(Build) 9990.00 root data:Selection", + "│ │ │ │ │ └─Selection 9990.00 cop[tikv] not(isnull(test.t1.b))", + "│ │ │ │ │ └─TableFullScan 10000.00 cop[tikv] table:t1 keep order:false, stats:pseudo", + "│ │ │ │ └─TableReader(Probe) 9980.01 root data:Selection", + "│ │ │ │ └─Selection 9980.01 cop[tikv] not(isnull(test.t2.a)), not(isnull(test.t2.b))", + "│ │ │ │ └─TableFullScan 10000.00 cop[tikv] table:t2 keep order:false, stats:pseudo", + "│ │ │ └─TableReader(Probe) 9980.01 root data:Selection", + "│ │ │ └─Selection 9980.01 cop[tikv] not(isnull(test.t.a)), not(isnull(test.t.b))", + "│ │ │ └─TableFullScan 10000.00 cop[tikv] table:t keep order:false, stats:pseudo", + "│ │ └─Sort(Probe) 9990.00 root test.t1.b", + "│ │ └─TableReader 9990.00 root data:Selection", + "│ │ └─Selection 9990.00 cop[tikv] not(isnull(test.t1.b))", + "│ │ └─TableFullScan 10000.00 cop[tikv] table:t1 keep order:false, stats:pseudo", "│ └─HashJoin(Probe) 12475.01 root inner join, equal:[eq(test.t.b, test.t1.b)]", "│ ├─TableReader(Build) 9990.00 root data:Selection", "│ │ └─Selection 9990.00 cop[tikv] not(isnull(test.t1.b))", @@ -5603,6 +5616,51 @@ "[planner:1815]Join hints are conflict, you can only specify one type of join", "[planner:1815]Optimizer aggregation hints are conflicted" ] + }, + { + "SQL": "explain with d1 as (\n select a from (\n select a from (\n select /*+ qb_name(qb, v4) use_index(t4@qb, idx_a) */ a from v4 where a < 10\n ) as t0 where a < 9\n ) as t1 where a < 8\n), d2 as (select /*+ qb_name(qb2, v4) use_index(t4@qb2, idx_b) */ a from v4 where b < 10)\n\nselect * from (select * from d1) as t0 join (select * from d2) as t1;", + "Plan": [ + "HashJoin_41 6944.44 root CARTESIAN inner join", + "├─IndexLookUp_50(Build) 83.33 root ", + "│ ├─IndexRangeScan_47(Build) 250.00 cop[tikv] table:t4, index:idx_b(b) range:(3,10), keep order:false, stats:pseudo", + "│ └─Selection_49(Probe) 83.33 cop[tikv] gt(test.t4.a, 2)", + "│ └─TableRowIDScan_48 250.00 cop[tikv] table:t4 keep order:false, stats:pseudo", + "└─IndexLookUp_46(Probe) 83.33 root ", + " ├─IndexRangeScan_43(Build) 250.00 cop[tikv] table:t4, index:idx_a(a) range:(2,8), keep order:false, stats:pseudo", + " └─Selection_45(Probe) 83.33 cop[tikv] gt(test.t4.b, 3)", + " └─TableRowIDScan_44 250.00 cop[tikv] table:t4 keep order:false, stats:pseudo" + ], + "Warn": null + }, + { + "SQL": "explain with d1 as (\n select a from (\n select a from (\n select a from v4 where a < 10\n ) as t0 where a < 9\n ) as t1 where a < 8\n), d2 as (select a from v4 where b < 10)\n\nselect /*+ qb_name(qb, v4@sel_4) use_index(t4@qb, idx_a) qb_name(qb2, v4@sel_5) use_index(t4@qb, idx_b) */ * from (select * from d1) as t0 join (select * from d2) as t1;", + "Plan": [ + "HashJoin_41 6944.44 root CARTESIAN inner join", + "├─TableReader_53(Build) 83.33 root data:Selection_52", + "│ └─Selection_52 83.33 cop[tikv] gt(test.t4.a, 2), gt(test.t4.b, 3), lt(test.t4.b, 10)", + "│ └─TableFullScan_51 10000.00 cop[tikv] table:t4 keep order:false, stats:pseudo", + "└─IndexLookUp_46(Probe) 83.33 root ", + " ├─IndexRangeScan_43(Build) 250.00 cop[tikv] table:t4, index:idx_a(a) range:(2,8), keep order:false, stats:pseudo", + " └─Selection_45(Probe) 83.33 cop[tikv] gt(test.t4.b, 3)", + " └─TableRowIDScan_44 250.00 cop[tikv] table:t4 keep order:false, stats:pseudo" + ], + "Warn": null + }, + { + "SQL": "explain with d1 as (\n select a from (\n select a from (\n select /*+ qb_name(qb, v5) use_index(t4@qb, idx_a) */ a from v4 where a < 10\n ) as t0 where a < 9\n ) as t1 where a < 8\n), d2 as (select /*+ qb_name(qb2, v4) use_index(t4@qb2, idx_b) */ a from v4 where b < 10)\n\nselect * from (select * from d1) as t0 join (select * from d2) as t1;", + "Plan": [ + "HashJoin_41 6944.44 root CARTESIAN inner join", + "├─IndexLookUp_57(Build) 83.33 root ", + "│ ├─IndexRangeScan_54(Build) 250.00 cop[tikv] table:t4, index:idx_b(b) range:(3,10), keep order:false, stats:pseudo", + "│ └─Selection_56(Probe) 83.33 cop[tikv] gt(test.t4.a, 2)", + "│ └─TableRowIDScan_55 250.00 cop[tikv] table:t4 keep order:false, stats:pseudo", + "└─TableReader_45(Probe) 83.33 root data:Selection_44", + " └─Selection_44 83.33 cop[tikv] gt(test.t4.a, 2), gt(test.t4.b, 3), lt(test.t4.a, 10), lt(test.t4.a, 8), lt(test.t4.a, 9)", + " └─TableFullScan_43 10000.00 cop[tikv] table:t4 keep order:false, stats:pseudo" + ], + "Warn": [ + "The qb_name hint qb is unused, please check whether the table list in the qb_name hint qb is correct" + ] } ] }, diff --git a/planner/optimize.go b/planner/optimize.go index 747dd5541596a..def76aba9c9c3 100644 --- a/planner/optimize.go +++ b/planner/optimize.go @@ -356,6 +356,7 @@ func optimize(ctx context.Context, sctx sessionctx.Context, node ast.Node, is in // build logical plan hintProcessor := &hint.BlockHintProcessor{Ctx: sctx} node.Accept(hintProcessor) + defer hintProcessor.HandleUnusedViewHints() builder := planBuilderPool.Get().(*core.PlanBuilder) defer planBuilderPool.Put(builder.ResetForReuse()) builder.Init(sctx, is, hintProcessor) diff --git a/session/BUILD.bazel b/session/BUILD.bazel index 2a79502bf985e..d0d68a9142035 100644 --- a/session/BUILD.bazel +++ b/session/BUILD.bazel @@ -136,6 +136,7 @@ go_test( "//expression", "//kv", "//meta", + "//meta/autoid", "//parser/ast", "//parser/auth", "//parser/model", diff --git a/session/schema_amender_test.go b/session/schema_amender_test.go index e82faba8e6e56..565b4861a9400 100644 --- a/session/schema_amender_test.go +++ b/session/schema_amender_test.go @@ -24,6 +24,7 @@ import ( "github.com/pingcap/kvproto/pkg/kvrpcpb" "github.com/pingcap/tidb/domain" "github.com/pingcap/tidb/kv" + "github.com/pingcap/tidb/meta/autoid" "github.com/pingcap/tidb/parser/model" "github.com/pingcap/tidb/parser/mysql" "github.com/pingcap/tidb/planner/core" @@ -276,7 +277,7 @@ func TestAmendCollectAndGenMutations(t *testing.T) { initTblColIdxID(oldTblMeta) // Indices[0] does not exist at the start. oldTblMeta.Indices = oldTblMeta.Indices[1:] - oldTbInfo, err := table.TableFromMeta(nil, oldTblMeta) + oldTbInfo, err := table.TableFromMeta(autoid.NewAllocators(false), oldTblMeta) require.NoError(t, err) oldTblMeta.Indices[0].State = startState oldTblMeta.Indices[2].State = endState @@ -296,7 +297,7 @@ func TestAmendCollectAndGenMutations(t *testing.T) { // The last index "c_d_e_str_prefix is dropped. newTblMeta.Indices = newTblMeta.Indices[:len(newTblMeta.Indices)-1] newTblMeta.Indices[0].Unique = false - newTblInfo, err := table.TableFromMeta(nil, newTblMeta) + newTblInfo, err := table.TableFromMeta(autoid.NewAllocators(false), newTblMeta) require.NoError(t, err) newTblMeta.Indices[0].State = endState // Indices[1] is newly created. diff --git a/session/session.go b/session/session.go index 74c5aa5730bd6..437c663999b83 100644 --- a/session/session.go +++ b/session/session.go @@ -145,6 +145,7 @@ var ( telemetryTablePartitionAddIntervalUsage = metrics.TelemetryTablePartitionAddIntervalPartitionsCnt telemetryTablePartitionDropIntervalUsage = metrics.TelemetryTablePartitionDropIntervalPartitionsCnt telemetryExchangePartitionUsage = metrics.TelemetryExchangePartitionCnt + telemetryTableCompactPartitionUsage = metrics.TelemetryCompactPartitionCnt telemetryLockUserUsage = metrics.TelemetryAccountLockCnt.WithLabelValues("lockUser") telemetryUnlockUserUsage = metrics.TelemetryAccountLockCnt.WithLabelValues("unlockUser") @@ -2897,11 +2898,17 @@ func InitMDLVariable(store kv.Storage) error { if err != nil { return err } + if isNull { + // Workaround for version: nightly-2022-11-07 to nightly-2022-11-17. + enable = true + logutil.BgLogger().Warn("metadata lock is null") + err = t.SetMetadataLock(true) + if err != nil { + return err + } + } return nil }) - if isNull { - return errors.New("metadata lock is null") - } variable.EnableMDL.Store(enable) return err } @@ -3631,6 +3638,9 @@ func (s *session) updateTelemetryMetric(es *executor.ExecStmt) { if ti.PartitionTelemetry.UseDropIntervalPartition { telemetryTablePartitionDropIntervalUsage.Inc() } + if ti.PartitionTelemetry.UseCompactTablePartition { + telemetryTableCompactPartitionUsage.Inc() + } } if ti.AccountLockTelemetry != nil { diff --git a/sessionctx/stmtctx/stmtctx.go b/sessionctx/stmtctx/stmtctx.go index 6c0f9003d6aef..c8fdc2ce32f2e 100644 --- a/sessionctx/stmtctx/stmtctx.go +++ b/sessionctx/stmtctx/stmtctx.go @@ -213,7 +213,7 @@ type StatementContext struct { warnings []SQLWarn errorCount uint16 execDetails execdetails.ExecDetails - allExecDetails []*execdetails.ExecDetails + allExecDetails []*execdetails.DetailsNeedP90 } // PrevAffectedRows is the affected-rows value(DDL is 0, DML is the number of affected rows). PrevAffectedRows int64 @@ -863,7 +863,7 @@ func (sc *StatementContext) resetMuForRetry() { sc.mu.errorCount = 0 sc.mu.warnings = nil sc.mu.execDetails = execdetails.ExecDetails{} - sc.mu.allExecDetails = make([]*execdetails.ExecDetails, 0, 4) + sc.mu.allExecDetails = make([]*execdetails.DetailsNeedP90, 0, 4) } // ResetForRetry resets the changed states during execution. @@ -887,7 +887,13 @@ func (sc *StatementContext) MergeExecDetails(details *execdetails.ExecDetails, c sc.mu.execDetails.RequestCount++ sc.MergeScanDetail(details.ScanDetail) sc.MergeTimeDetail(details.TimeDetail) - sc.mu.allExecDetails = append(sc.mu.allExecDetails, details) + sc.mu.allExecDetails = append(sc.mu.allExecDetails, + &execdetails.DetailsNeedP90{ + BackoffSleep: details.BackoffSleep, + BackoffTimes: details.BackoffTimes, + CalleeAddress: details.CalleeAddress, + TimeDetail: details.TimeDetail, + }) } if commitDetails != nil { if sc.mu.execDetails.CommitDetail == nil { @@ -1006,14 +1012,14 @@ func (sc *StatementContext) CopTasksDetails() *CopTasksDetails { d.AvgProcessTime = sc.mu.execDetails.TimeDetail.ProcessTime / time.Duration(n) d.AvgWaitTime = sc.mu.execDetails.TimeDetail.WaitTime / time.Duration(n) - slices.SortFunc(sc.mu.allExecDetails, func(i, j *execdetails.ExecDetails) bool { + slices.SortFunc(sc.mu.allExecDetails, func(i, j *execdetails.DetailsNeedP90) bool { return i.TimeDetail.ProcessTime < j.TimeDetail.ProcessTime }) d.P90ProcessTime = sc.mu.allExecDetails[n*9/10].TimeDetail.ProcessTime d.MaxProcessTime = sc.mu.allExecDetails[n-1].TimeDetail.ProcessTime d.MaxProcessAddress = sc.mu.allExecDetails[n-1].CalleeAddress - slices.SortFunc(sc.mu.allExecDetails, func(i, j *execdetails.ExecDetails) bool { + slices.SortFunc(sc.mu.allExecDetails, func(i, j *execdetails.DetailsNeedP90) bool { return i.TimeDetail.WaitTime < j.TimeDetail.WaitTime }) d.P90WaitTime = sc.mu.allExecDetails[n*9/10].TimeDetail.WaitTime diff --git a/sessionctx/stmtctx/stmtctx_test.go b/sessionctx/stmtctx/stmtctx_test.go index cc21b3e4812c7..67520c36e7b80 100644 --- a/sessionctx/stmtctx/stmtctx_test.go +++ b/sessionctx/stmtctx/stmtctx_test.go @@ -36,12 +36,14 @@ func TestCopTasksDetails(t *testing.T) { backoffs := []string{"tikvRPC", "pdRPC", "regionMiss"} for i := 0; i < 100; i++ { d := &execdetails.ExecDetails{ - CalleeAddress: fmt.Sprintf("%v", i+1), - BackoffSleep: make(map[string]time.Duration), - BackoffTimes: make(map[string]int), - TimeDetail: util.TimeDetail{ - ProcessTime: time.Second * time.Duration(i+1), - WaitTime: time.Millisecond * time.Duration(i+1), + DetailsNeedP90: execdetails.DetailsNeedP90{ + CalleeAddress: fmt.Sprintf("%v", i+1), + BackoffSleep: make(map[string]time.Duration), + BackoffTimes: make(map[string]int), + TimeDetail: util.TimeDetail{ + ProcessTime: time.Second * time.Duration(i+1), + WaitTime: time.Millisecond * time.Duration(i+1), + }, }, } for _, backoff := range backoffs { diff --git a/sessionctx/variable/session_test.go b/sessionctx/variable/session_test.go index 92049902618c2..732ce4ad606cf 100644 --- a/sessionctx/variable/session_test.go +++ b/sessionctx/variable/session_test.go @@ -164,9 +164,11 @@ func TestSlowLogFormat(t *testing.T) { ProcessedKeys: 20001, TotalKeys: 10000, }, - TimeDetail: util.TimeDetail{ - ProcessTime: time.Second * time.Duration(2), - WaitTime: time.Minute, + DetailsNeedP90: execdetails.DetailsNeedP90{ + TimeDetail: util.TimeDetail{ + ProcessTime: time.Second * time.Duration(2), + WaitTime: time.Minute, + }, }, } statsInfos := make(map[string]uint64) diff --git a/table/table.go b/table/table.go index 6aef5ed4497e6..813131df90896 100644 --- a/table/table.go +++ b/table/table.go @@ -206,7 +206,8 @@ func AllocAutoIncrementValue(ctx context.Context, t Table, sctx sessionctx.Conte } increment := sctx.GetSessionVars().AutoIncrementIncrement offset := sctx.GetSessionVars().AutoIncrementOffset - _, max, err := t.Allocators(sctx).Get(autoid.RowIDAllocType).Alloc(ctx, uint64(1), int64(increment), int64(offset)) + alloc := t.Allocators(sctx).Get(autoid.AutoIncrementType) + _, max, err := alloc.Alloc(ctx, uint64(1), int64(increment), int64(offset)) if err != nil { return 0, err } @@ -218,7 +219,8 @@ func AllocAutoIncrementValue(ctx context.Context, t Table, sctx sessionctx.Conte func AllocBatchAutoIncrementValue(ctx context.Context, t Table, sctx sessionctx.Context, N int) (firstID int64, increment int64, err error) { increment = int64(sctx.GetSessionVars().AutoIncrementIncrement) offset := int64(sctx.GetSessionVars().AutoIncrementOffset) - min, max, err := t.Allocators(sctx).Get(autoid.RowIDAllocType).Alloc(ctx, uint64(N), increment, offset) + alloc := t.Allocators(sctx).Get(autoid.AutoIncrementType) + min, max, err := alloc.Alloc(ctx, uint64(N), increment, offset) if err != nil { return min, max, err } diff --git a/table/tables/tables.go b/table/tables/tables.go index 825f05d7ffa2e..9a5eaae0d6096 100644 --- a/table/tables/tables.go +++ b/table/tables/tables.go @@ -85,7 +85,7 @@ func MockTableFromMeta(tblInfo *model.TableInfo) table.Table { } var t TableCommon - initTableCommon(&t, tblInfo, tblInfo.ID, columns, nil) + initTableCommon(&t, tblInfo, tblInfo.ID, columns, autoid.NewAllocators(false)) if tblInfo.TableCacheStatusType != model.TableCacheStatusDisable { ret, err := newCachedTable(&t) if err != nil { @@ -1547,7 +1547,7 @@ func (t *TableCommon) Allocators(ctx sessionctx.Context) autoid.Allocators { // Use an independent allocator for global temporary tables. if t.meta.TempTableType == model.TempTableGlobal { if alloc := ctx.GetSessionVars().GetTemporaryTable(t.meta).GetAutoIDAllocator(); alloc != nil { - return autoid.Allocators{alloc} + return autoid.NewAllocators(false, alloc) } // If the session is not in a txn, for example, in "show create table", use the original allocator. // Otherwise the would be a nil pointer dereference. @@ -1557,8 +1557,9 @@ func (t *TableCommon) Allocators(ctx sessionctx.Context) autoid.Allocators { // Replace the row id allocator with the one in session variables. sessAlloc := ctx.GetSessionVars().IDAllocator - retAllocs := make([]autoid.Allocator, 0, len(t.allocs)) - copy(retAllocs, t.allocs) + allocs := t.allocs.Allocs + retAllocs := make([]autoid.Allocator, 0, len(allocs)) + copy(retAllocs, allocs) overwritten := false for i, a := range retAllocs { @@ -1571,7 +1572,7 @@ func (t *TableCommon) Allocators(ctx sessionctx.Context) autoid.Allocators { if !overwritten { retAllocs = append(retAllocs, sessAlloc) } - return retAllocs + return autoid.NewAllocators(t.allocs.SepAutoInc, retAllocs...) } // Type implements table.Table Type interface. @@ -1925,7 +1926,7 @@ func maxIndexLen(idxA, idxB *model.IndexColumn) *model.IndexColumn { } func getSequenceAllocator(allocs autoid.Allocators) (autoid.Allocator, error) { - for _, alloc := range allocs { + for _, alloc := range allocs.Allocs { if alloc.GetType() == autoid.SequenceType { return alloc, nil } diff --git a/table/tables/tables_test.go b/table/tables/tables_test.go index d659f918a8168..661770b868383 100644 --- a/table/tables/tables_test.go +++ b/table/tables/tables_test.go @@ -378,18 +378,18 @@ func TestTableFromMeta(t *testing.T) { // For test coverage tbInfo.Columns[0].GeneratedExprString = "a" - _, err = tables.TableFromMeta(nil, tbInfo) + _, err = tables.TableFromMeta(autoid.NewAllocators(false), tbInfo) require.NoError(t, err) tbInfo.Columns[0].GeneratedExprString = "test" - _, err = tables.TableFromMeta(nil, tbInfo) + _, err = tables.TableFromMeta(autoid.NewAllocators(false), tbInfo) require.Error(t, err) tbInfo.Columns[0].State = model.StateNone - tb, err = tables.TableFromMeta(nil, tbInfo) + tb, err = tables.TableFromMeta(autoid.NewAllocators(false), tbInfo) require.Nil(t, tb) require.Error(t, err) tbInfo.State = model.StateNone - tb, err = tables.TableFromMeta(nil, tbInfo) + tb, err = tables.TableFromMeta(autoid.NewAllocators(false), tbInfo) require.Nil(t, tb) require.Error(t, err) diff --git a/table/temptable/BUILD.bazel b/table/temptable/BUILD.bazel index 30c41bd1c55b3..8487a26533b51 100644 --- a/table/temptable/BUILD.bazel +++ b/table/temptable/BUILD.bazel @@ -41,6 +41,7 @@ go_test( deps = [ "//infoschema", "//kv", + "//meta/autoid", "//parser/model", "//parser/mysql", "//sessionctx", diff --git a/table/temptable/ddl.go b/table/temptable/ddl.go index ccad2b7b0214c..d464cb3c48618 100644 --- a/table/temptable/ddl.go +++ b/table/temptable/ddl.go @@ -182,7 +182,7 @@ func newTemporaryTableFromTableInfo(sctx sessionctx.Context, tbInfo *model.Table if alloc != nil { allocs = append(allocs, alloc) } - return tables.TableFromMeta(allocs, tbInfo) + return tables.TableFromMeta(autoid.NewAllocators(false, allocs...), tbInfo) } // GetTemporaryTableDDL gets the temptable.TemporaryTableDDL from session context diff --git a/table/temptable/main_test.go b/table/temptable/main_test.go index 7dbc5e86d37d9..8c5c4f557e1ae 100644 --- a/table/temptable/main_test.go +++ b/table/temptable/main_test.go @@ -22,6 +22,7 @@ import ( "github.com/pingcap/tidb/infoschema" "github.com/pingcap/tidb/kv" + "github.com/pingcap/tidb/meta/autoid" "github.com/pingcap/tidb/parser/model" "github.com/pingcap/tidb/parser/mysql" "github.com/pingcap/tidb/table" @@ -86,7 +87,7 @@ func (is *mockedInfoSchema) TableByID(tblID int64) (table.Table, bool) { State: model.StatePublic, } - tbl, err := table.TableFromMeta(nil, tblInfo) + tbl, err := table.TableFromMeta(autoid.NewAllocators(false), tblInfo) require.NoError(is.t, err) return tbl, true diff --git a/telemetry/data_feature_usage_test.go b/telemetry/data_feature_usage_test.go index 770f4a7d3d08e..ebe93d6dbaa52 100644 --- a/telemetry/data_feature_usage_test.go +++ b/telemetry/data_feature_usage_test.go @@ -143,7 +143,7 @@ func TestAutoIDNoCache(t *testing.T) { usage, err = telemetry.GetFeatureUsage(tk.Session()) require.NoError(t, err) require.True(t, usage.AutoIDNoCache) - tk.MustExec("alter table tele_autoid auto_id_cache=0") + tk.MustExec("drop table tele_autoid") usage, err = telemetry.GetFeatureUsage(tk.Session()) require.NoError(t, err) require.False(t, usage.AutoIDNoCache) @@ -286,6 +286,12 @@ func TestTablePartition(t *testing.T) { usage, err = telemetry.GetFeatureUsage(tk.Session()) require.NoError(t, err) require.Equal(t, int64(1), usage.ExchangePartition.ExchangePartitionCnt) + + require.Equal(t, int64(0), usage.TablePartition.TablePartitionComactCnt) + tk.MustExec(`alter table pt2 compact partition p0 tiflash replica;`) + usage, err = telemetry.GetFeatureUsage(tk.Session()) + require.NoError(t, err) + require.Equal(t, int64(1), usage.TablePartition.TablePartitionComactCnt) } func TestPlacementPolicies(t *testing.T) { diff --git a/util/execdetails/execdetails.go b/util/execdetails/execdetails.go index 76e468cf38f50..e3652b2c49aec 100644 --- a/util/execdetails/execdetails.go +++ b/util/execdetails/execdetails.go @@ -32,19 +32,24 @@ import ( // ExecDetails contains execution detail information. type ExecDetails struct { - BackoffSleep map[string]time.Duration - BackoffTimes map[string]int + DetailsNeedP90 CommitDetail *util.CommitDetails LockKeysDetail *util.LockKeysDetails ScanDetail *util.ScanDetail - CalleeAddress string - TimeDetail util.TimeDetail CopTime time.Duration BackoffTime time.Duration LockKeysDuration time.Duration RequestCount int } +// DetailsNeedP90 contains execution detail information which need calculate P90. +type DetailsNeedP90 struct { + BackoffSleep map[string]time.Duration + BackoffTimes map[string]int + CalleeAddress string + TimeDetail util.TimeDetail +} + type stmtExecDetailKeyType struct{} // StmtExecDetailKey used to carry StmtExecDetail info in context.Context. @@ -320,7 +325,9 @@ func (d ExecDetails) ToZapFields() (fields []zap.Field) { type basicCopRuntimeStats struct { storeType string BasicRuntimeStats - threads int32 + threads int32 + totalTasks int32 + procTimes []time.Duration } // String implements the RuntimeStats interface. @@ -337,6 +344,8 @@ func (e *basicCopRuntimeStats) Clone() RuntimeStats { BasicRuntimeStats: BasicRuntimeStats{loop: e.loop, consume: e.consume, rows: e.rows, tiflashScanContext: e.tiflashScanContext.Clone()}, threads: e.threads, storeType: e.storeType, + totalTasks: e.totalTasks, + procTimes: e.procTimes, } } @@ -350,6 +359,13 @@ func (e *basicCopRuntimeStats) Merge(rs RuntimeStats) { e.consume += tmp.consume e.rows += tmp.rows e.threads += tmp.threads + e.totalTasks += tmp.totalTasks + if len(tmp.procTimes) > 0 { + e.procTimes = append(e.procTimes, tmp.procTimes...) + } else { + e.procTimes = append(e.procTimes, time.Duration(tmp.consume)) + } + e.tiflashScanContext.Merge(tmp.tiflashScanContext) } // Tp implements the RuntimeStats interface. @@ -364,7 +380,7 @@ type CopRuntimeStats struct { // have many region leaders, several coprocessor tasks can be sent to the // same tikv-server instance. We have to use a list to maintain all tasks // executed on each instance. - stats map[string][]*basicCopRuntimeStats + stats map[string]*basicCopRuntimeStats scanDetail *util.ScanDetail // do not use kv.StoreType because it will meet cycle import error storeType string @@ -376,8 +392,14 @@ func (crs *CopRuntimeStats) RecordOneCopTask(address string, summary *tipb.Execu crs.Lock() defer crs.Unlock() - crs.stats[address] = append(crs.stats[address], - &basicCopRuntimeStats{BasicRuntimeStats: BasicRuntimeStats{loop: int32(*summary.NumIterations), + if crs.stats[address] == nil { + crs.stats[address] = &basicCopRuntimeStats{ + storeType: crs.storeType, + } + } + crs.stats[address].Merge(&basicCopRuntimeStats{ + storeType: crs.storeType, + BasicRuntimeStats: BasicRuntimeStats{loop: int32(*summary.NumIterations), consume: int64(*summary.TimeProcessedNs), rows: int64(*summary.NumProducedRows), tiflashScanContext: TiFlashScanContext{ @@ -387,17 +409,15 @@ func (crs *CopRuntimeStats) RecordOneCopTask(address string, summary *tipb.Execu totalDmfileSkippedRows: summary.GetTiflashScanContext().GetTotalDmfileSkippedRows(), totalDmfileRoughSetIndexLoadTimeMs: summary.GetTiflashScanContext().GetTotalDmfileRoughSetIndexLoadTimeMs(), totalDmfileReadTimeMs: summary.GetTiflashScanContext().GetTotalDmfileReadTimeMs(), - totalCreateSnapshotTimeMs: summary.GetTiflashScanContext().GetTotalCreateSnapshotTimeMs()}}, - threads: int32(summary.GetConcurrency()), - storeType: crs.storeType}) + totalCreateSnapshotTimeMs: summary.GetTiflashScanContext().GetTotalCreateSnapshotTimeMs()}}, threads: int32(summary.GetConcurrency()), + totalTasks: 1, + }) } // GetActRows return total rows of CopRuntimeStats. func (crs *CopRuntimeStats) GetActRows() (totalRows int64) { for _, instanceStats := range crs.stats { - for _, stat := range instanceStats { - totalRows += stat.rows - } + totalRows += instanceStats.rows } return totalRows } @@ -407,14 +427,12 @@ func (crs *CopRuntimeStats) MergeBasicStats() (procTimes []time.Duration, totalT procTimes = make([]time.Duration, 0, 32) totalTiFlashScanContext = TiFlashScanContext{} for _, instanceStats := range crs.stats { - for _, stat := range instanceStats { - procTimes = append(procTimes, time.Duration(stat.consume)*time.Nanosecond) - totalTime += time.Duration(stat.consume) - totalLoops += stat.loop - totalThreads += stat.threads - totalTiFlashScanContext.Merge(stat.tiflashScanContext) - totalTasks++ - } + procTimes = append(procTimes, instanceStats.procTimes...) + totalTime += time.Duration(instanceStats.consume) + totalLoops += instanceStats.loop + totalThreads += instanceStats.threads + totalTiFlashScanContext.Merge(instanceStats.tiflashScanContext) + totalTasks += instanceStats.totalTasks } return } @@ -597,57 +615,23 @@ func (*BasicRuntimeStats) Tp() int { // RootRuntimeStats is the executor runtime stats that combine with multiple runtime stats. type RootRuntimeStats struct { - basics []*BasicRuntimeStats - groupRss [][]RuntimeStats + basic *BasicRuntimeStats + groupRss []RuntimeStats } -// GetActRows return total rows of RootRuntimeStats. -func (e *RootRuntimeStats) GetActRows() int64 { - num := int64(0) - for _, basic := range e.basics { - num += basic.GetActRows() - } - return num -} - -// MergeBasicStats merges BasicRuntimeStats in the RootRuntimeStats into single one. -func (e *RootRuntimeStats) MergeBasicStats() *BasicRuntimeStats { - if len(e.basics) == 0 { - return nil - } - basic := e.basics[0].Clone().(*BasicRuntimeStats) - for i := 1; i < len(e.basics); i++ { - basic.Merge(e.basics[i]) - } - return basic +// NewRootRuntimeStats returns a new RootRuntimeStats +func NewRootRuntimeStats() *RootRuntimeStats { + return &RootRuntimeStats{basic: &BasicRuntimeStats{}} } -// MergeGroupStats merges every slice in e.groupRss into single RuntimeStats. -func (e *RootRuntimeStats) MergeGroupStats() (res []RuntimeStats) { - if len(e.groupRss) == 0 { - return nil - } - for _, rss := range e.groupRss { - if len(rss) == 0 { - continue - } else if len(rss) == 1 { - res = append(res, rss[0]) - continue - } - rs := rss[0].Clone() - for i := 1; i < len(rss); i++ { - rs.Merge(rss[i]) - } - res = append(res, rs) - } - return +// GetActRows return total rows of RootRuntimeStats. +func (e *RootRuntimeStats) GetActRows() int64 { + return e.basic.rows } // MergeStats merges stats in the RootRuntimeStats and return the stats suitable for display directly. func (e *RootRuntimeStats) MergeStats() (basic *BasicRuntimeStats, groups []RuntimeStats) { - basic = e.MergeBasicStats() - groups = e.MergeGroupStats() - return + return e.basic, e.groupRss } // String implements the RuntimeStats interface. @@ -729,38 +713,46 @@ func (e *RuntimeStatsColl) RegisterStats(planID int, info RuntimeStats) { e.mu.Lock() stats, ok := e.rootStats[planID] if !ok { - stats = &RootRuntimeStats{} + stats = NewRootRuntimeStats() e.rootStats[planID] = stats } - if basic, ok := info.(*BasicRuntimeStats); ok { - stats.basics = append(stats.basics, basic) - } else { - tp := info.Tp() - found := false - for i, rss := range stats.groupRss { - if len(rss) == 0 { - continue - } - if rss[0].Tp() == tp { - stats.groupRss[i] = append(stats.groupRss[i], info) - found = true - break - } - } - if !found { - stats.groupRss = append(stats.groupRss, []RuntimeStats{info}) + tp := info.Tp() + found := false + for _, rss := range stats.groupRss { + if rss.Tp() == tp { + rss.Merge(info) + found = true + break } } + if !found { + stats.groupRss = append(stats.groupRss, info.Clone()) + } e.mu.Unlock() } +// GetBasicRuntimeStats gets basicRuntimeStats for a executor. +func (e *RuntimeStatsColl) GetBasicRuntimeStats(planID int) *BasicRuntimeStats { + e.mu.Lock() + defer e.mu.Unlock() + stats, ok := e.rootStats[planID] + if !ok { + stats = NewRootRuntimeStats() + e.rootStats[planID] = stats + } + if stats.basic == nil { + stats.basic = &BasicRuntimeStats{} + } + return stats.basic +} + // GetRootStats gets execStat for a executor. func (e *RuntimeStatsColl) GetRootStats(planID int) *RootRuntimeStats { e.mu.Lock() defer e.mu.Unlock() runtimeStats, exists := e.rootStats[planID] if !exists { - runtimeStats = &RootRuntimeStats{} + runtimeStats = NewRootRuntimeStats() e.rootStats[planID] = runtimeStats } return runtimeStats @@ -784,7 +776,7 @@ func (e *RuntimeStatsColl) GetOrCreateCopStats(planID int, storeType string) *Co copStats, ok := e.copStats[planID] if !ok { copStats = &CopRuntimeStats{ - stats: make(map[string][]*basicCopRuntimeStats), + stats: make(map[string]*basicCopRuntimeStats), scanDetail: &util.ScanDetail{}, storeType: storeType, } diff --git a/util/execdetails/execdetails_test.go b/util/execdetails/execdetails_test.go index 2740e10b321cb..a7c17ca43db87 100644 --- a/util/execdetails/execdetails_test.go +++ b/util/execdetails/execdetails_test.go @@ -109,10 +109,10 @@ func TestString(t *testing.T) { RocksdbBlockReadByte: 100, RocksdbBlockReadDuration: time.Millisecond, }, - TimeDetail: util.TimeDetail{ + DetailsNeedP90: DetailsNeedP90{TimeDetail: util.TimeDetail{ ProcessTime: 2*time.Second + 5*time.Millisecond, WaitTime: time.Second, - }, + }}, } expected := "Cop_time: 1.003 Process_time: 2.005 Wait_time: 1 Backoff_time: 1 Request_count: 1 Prewrite_time: 1 Commit_time: " + "1 Get_commit_ts_time: 1 Get_latest_ts_time: 1 Commit_backoff_time: 1 " + @@ -179,9 +179,11 @@ func TestCopRuntimeStats(t *testing.T) { copStats := cop.stats["8.8.8.8"] require.NotNil(t, copStats) - copStats[0].SetRowNum(10) - copStats[0].Record(time.Second, 10) - require.Equal(t, "time:1s, loops:2", copStats[0].String()) + newCopStats := &basicCopRuntimeStats{} + newCopStats.SetRowNum(10) + newCopStats.Record(time.Second, 10) + copStats.Merge(newCopStats) + require.Equal(t, "time:1s, loops:2", copStats.String()) require.Equal(t, "tikv_task:{proc max:4ns, min:3ns, avg: 3ns, p80:4ns, p95:4ns, iters:7, tasks:2}", stats.GetOrCreateCopStats(aggID, "tikv").String()) rootStats := stats.GetRootStats(tableReaderID) @@ -193,7 +195,7 @@ func TestCopRuntimeStats(t *testing.T) { cop.scanDetail.RocksdbKeySkippedCount = 0 cop.scanDetail.RocksdbBlockReadCount = 0 // Print all fields even though the value of some fields is 0. - str := "tikv_task:{proc max:1s, min:2ns, avg: 500ms, p80:1s, p95:1s, iters:4, tasks:2}, " + + str := "tikv_task:{proc max:1s, min:1ns, avg: 500ms, p80:1s, p95:1s, iters:4, tasks:2}, " + "scan_detail: {total_keys: 15, rocksdb: {delete_skipped_count: 5, block: {cache_hit_count: 10, read_byte: 100 Bytes}}}" require.Equal(t, str, cop.String()) @@ -228,9 +230,9 @@ func TestCopRuntimeStatsForTiFlash(t *testing.T) { copStats := cop.stats["8.8.8.8"] require.NotNil(t, copStats) - copStats[0].SetRowNum(10) - copStats[0].Record(time.Second, 10) - require.Equal(t, "time:1s, loops:2, threads:1, tiflash_scan:{dmfile:{total_scanned_packs:1, total_skipped_packs:0, total_scanned_rows:8192, total_skipped_rows:0, total_rough_set_index_load_time: 15ms, total_read_time: 200ms}, total_create_snapshot_time: 40ms}", copStats[0].String()) + copStats.SetRowNum(10) + copStats.Record(time.Second, 10) + require.Equal(t, "time:1s, loops:2, threads:1, tiflash_scan:{dmfile:{total_scanned_packs:1, total_skipped_packs:0, total_scanned_rows:8192, total_skipped_rows:0, total_rough_set_index_load_time: 15ms, total_read_time: 200ms}, total_create_snapshot_time: 40ms}", copStats.String()) expected := "tiflash_task:{proc max:4ns, min:3ns, avg: 3ns, p80:4ns, p95:4ns, iters:7, tasks:2, threads:2}, tiflash_scan:{dmfile:{total_scanned_packs:3, total_skipped_packs:11, total_scanned_rows:20192, total_skipped_rows:86000, total_rough_set_index_load_time: 100ms, total_read_time: 3000ms}, total_create_snapshot_time: 50ms}" require.Equal(t, expected, stats.GetOrCreateCopStats(aggID, "tiflash").String()) @@ -385,17 +387,14 @@ func TestRuntimeStatsWithCommit(t *testing.T) { } func TestRootRuntimeStats(t *testing.T) { - basic1 := &BasicRuntimeStats{} - basic2 := &BasicRuntimeStats{} - basic1.Record(time.Second, 20) - basic2.Record(time.Second*2, 30) pid := 1 stmtStats := NewRuntimeStatsColl(nil) - stmtStats.RegisterStats(pid, basic1) - stmtStats.RegisterStats(pid, basic2) + basic1 := stmtStats.GetBasicRuntimeStats(pid) + basic2 := stmtStats.GetBasicRuntimeStats(pid) + basic1.Record(time.Second, 20) + basic2.Record(time.Second*2, 30) concurrency := &RuntimeStatsWithConcurrencyInfo{} concurrency.SetConcurrencyInfo(NewConcurrencyInfo("worker", 15)) - stmtStats.RegisterStats(pid, concurrency) commitDetail := &util.CommitDetails{ GetCommitTsTime: time.Second, PrewriteTime: time.Second, @@ -405,6 +404,7 @@ func TestRootRuntimeStats(t *testing.T) { PrewriteRegionNum: 5, TxnRetry: 2, } + stmtStats.RegisterStats(pid, concurrency) stmtStats.RegisterStats(pid, &RuntimeStatsWithCommit{ Commit: commitDetail, }) diff --git a/util/hint/hint_processor.go b/util/hint/hint_processor.go index b087981abd409..be1a1a4e7fc4c 100644 --- a/util/hint/hint_processor.go +++ b/util/hint/hint_processor.go @@ -325,8 +325,9 @@ type BlockHintProcessor struct { QbHints map[int][]*ast.TableOptimizerHint // Group all hints at same query block. // Used for the view's hint - QbNameMap4View map[string][]ast.HintTable // Map from view's query block name to view's table list. - QbHints4View map[string][]*ast.TableOptimizerHint // Group all hints at same query block for view hints. + QbNameMap4View map[string][]ast.HintTable // Map from view's query block name to view's table list. + QbHints4View map[string][]*ast.TableOptimizerHint // Group all hints at same query block for view hints. + QbNameUsed4View map[string]struct{} // Store all the qb_name hints which are used for view Ctx sessionctx.Context selectStmtOffset int @@ -346,15 +347,14 @@ func (p *BlockHintProcessor) Enter(in ast.Node) (ast.Node, bool) { p.checkQueryBlockHints(node.TableHints, 0) case *ast.SelectStmt: p.selectStmtOffset++ - // Only support view hints which appear in the outer select part - if p.selectStmtOffset == 1 { - // Handle the view hints and update the left hint. - node.TableHints = p.handleViewHints(node.TableHints) - } node.QueryBlockOffset = p.selectStmtOffset + // Handle the view hints and update the left hint. + node.TableHints = p.handleViewHints(node.TableHints, node.QueryBlockOffset) p.checkQueryBlockHints(node.TableHints, node.QueryBlockOffset) case *ast.ExplainStmt: return in, true + case *ast.CreateBindingStmt: + return in, true } return in, false } @@ -373,12 +373,6 @@ func (p *BlockHintProcessor) checkQueryBlockHints(hints []*ast.TableOptimizerHin if hint.HintName.L != hintQBName { continue } - if offset > 1 && len(hint.Tables) > 0 { - if p.Ctx != nil { - p.Ctx.GetSessionVars().StmtCtx.AppendWarning(fmt.Errorf("The qb_name hint for view only supports to be defined in the first query block")) - } - continue - } if qbName != "" { if p.Ctx != nil { p.Ctx.GetSessionVars().StmtCtx.AppendWarning(fmt.Errorf("There are more than two query names in same query block, using the first one %s", qbName)) @@ -402,7 +396,7 @@ func (p *BlockHintProcessor) checkQueryBlockHints(hints []*ast.TableOptimizerHin } } -func (p *BlockHintProcessor) handleViewHints(hints []*ast.TableOptimizerHint) (leftHints []*ast.TableOptimizerHint) { +func (p *BlockHintProcessor) handleViewHints(hints []*ast.TableOptimizerHint, offset int) (leftHints []*ast.TableOptimizerHint) { if len(hints) == 0 { return } @@ -416,6 +410,7 @@ func (p *BlockHintProcessor) handleViewHints(hints []*ast.TableOptimizerHint) (l usedHints[i] = true if p.QbNameMap4View == nil { p.QbNameMap4View = make(map[string][]ast.HintTable) + p.QbNameUsed4View = make(map[string]struct{}) } qbName := hint.QBName.L if qbName == "" { @@ -426,6 +421,14 @@ func (p *BlockHintProcessor) handleViewHints(hints []*ast.TableOptimizerHint) (l p.Ctx.GetSessionVars().StmtCtx.AppendWarning(fmt.Errorf("Duplicate query block name %s for view's query block hint, only the first one is effective", qbName)) } } else { + if offset != 1 { + // If there are some qb_name hints for view are not defined in the first query block, + // we should add the query block number where it is located to the first table in the view's qb_name hint table list. + qbNum := hint.Tables[0].QBName.L + if qbNum == "" { + hint.Tables[0].QBName = model.NewCIStr(fmt.Sprintf("%s%d", defaultSelectBlockPrefix, offset)) + } + } p.QbNameMap4View[qbName] = hint.Tables } } @@ -475,6 +478,18 @@ func (p *BlockHintProcessor) handleViewHints(hints []*ast.TableOptimizerHint) (l return } +// HandleUnusedViewHints handle the unused view hints. +func (p *BlockHintProcessor) HandleUnusedViewHints() { + if p.QbNameMap4View != nil { + for qbName := range p.QbNameMap4View { + _, ok := p.QbNameUsed4View[qbName] + if !ok && p.Ctx != nil { + p.Ctx.GetSessionVars().StmtCtx.AppendWarning(fmt.Errorf("The qb_name hint %s is unused, please check whether the table list in the qb_name hint %s is correct", qbName, qbName)) + } + } + } +} + const ( defaultUpdateBlockName = "upd_1" defaultDeleteBlockName = "del_1" diff --git a/util/stmtsummary/statement_summary_test.go b/util/stmtsummary/statement_summary_test.go index 8ee767f2342e0..ac7e1b06e059b 100644 --- a/util/stmtsummary/statement_summary_test.go +++ b/util/stmtsummary/statement_summary_test.go @@ -175,9 +175,8 @@ func TestAddStatement(t *testing.T) { MaxWaitTime: 2500, }, ExecDetail: &execdetails.ExecDetails{ - CalleeAddress: "202", - BackoffTime: 180, - RequestCount: 20, + BackoffTime: 180, + RequestCount: 20, CommitDetail: &util.CommitDetails{ GetCommitTsTime: 500, PrewriteTime: 50000, @@ -214,9 +213,11 @@ func TestAddStatement(t *testing.T) { RocksdbBlockReadCount: 10, RocksdbBlockReadByte: 1000, }, - TimeDetail: util.TimeDetail{ - ProcessTime: 1500, - WaitTime: 150, + DetailsNeedP90: execdetails.DetailsNeedP90{ + TimeDetail: util.TimeDetail{ + ProcessTime: 1500, + WaitTime: 150, + }, CalleeAddress: "202", }, }, StmtCtx: &stmtctx.StatementContext{ @@ -313,9 +314,8 @@ func TestAddStatement(t *testing.T) { MaxWaitTime: 250, }, ExecDetail: &execdetails.ExecDetails{ - CalleeAddress: "302", - BackoffTime: 18, - RequestCount: 2, + BackoffTime: 18, + RequestCount: 2, CommitDetail: &util.CommitDetails{ GetCommitTsTime: 50, PrewriteTime: 5000, @@ -352,9 +352,12 @@ func TestAddStatement(t *testing.T) { RocksdbBlockReadCount: 10, RocksdbBlockReadByte: 1000, }, - TimeDetail: util.TimeDetail{ - ProcessTime: 150, - WaitTime: 15, + DetailsNeedP90: execdetails.DetailsNeedP90{ + TimeDetail: util.TimeDetail{ + ProcessTime: 150, + WaitTime: 15, + }, + CalleeAddress: "302", }, }, StmtCtx: &stmtctx.StatementContext{ @@ -605,9 +608,8 @@ func generateAnyExecInfo() *StmtExecInfo { MaxWaitTime: 1500, }, ExecDetail: &execdetails.ExecDetails{ - CalleeAddress: "129", - BackoffTime: 80, - RequestCount: 10, + BackoffTime: 80, + RequestCount: 10, CommitDetail: &util.CommitDetails{ GetCommitTsTime: 100, PrewriteTime: 10000, @@ -644,9 +646,12 @@ func generateAnyExecInfo() *StmtExecInfo { RocksdbBlockReadCount: 10, RocksdbBlockReadByte: 1000, }, - TimeDetail: util.TimeDetail{ - ProcessTime: 500, - WaitTime: 50, + DetailsNeedP90: execdetails.DetailsNeedP90{ + TimeDetail: util.TimeDetail{ + ProcessTime: 500, + WaitTime: 50, + }, + CalleeAddress: "129", }, }, StmtCtx: &stmtctx.StatementContext{