@@ -689,15 +689,25 @@ func (e *memtableRetriever) setDataFromOneTable(
689
689
return rows , nil
690
690
}
691
691
692
- func (e * memtableRetriever ) setDataFromTables (ctx context.Context , sctx sessionctx.Context ) error {
693
- useStatsCache := e .updateStatsCacheIfNeed ()
694
- checker := privilege .GetPrivilegeManager (sctx )
692
+ func onlySchemaOrTableColumns (columns []* model.ColumnInfo ) bool {
693
+ if len (columns ) <= 3 {
694
+ for _ , colInfo := range columns {
695
+ switch colInfo .Name .L {
696
+ case "table_schema" :
697
+ case "table_name" :
698
+ case "table_catalog" :
699
+ default :
700
+ return false
701
+ }
702
+ }
703
+ return true
704
+ }
705
+ return false
706
+ }
695
707
708
+ func (e * memtableRetriever ) setDataFromTables (ctx context.Context , sctx sessionctx.Context ) error {
696
709
var rows [][]types.Datum
697
- loc := sctx .GetSessionVars ().TimeZone
698
- if loc == nil {
699
- loc = time .Local
700
- }
710
+ checker := privilege .GetPrivilegeManager (sctx )
701
711
ex , ok := e .extractor .(* plannercore.InfoSchemaTablesExtractor )
702
712
if ! ok {
703
713
return errors .Errorf ("wrong extractor type: %T, expected InfoSchemaTablesExtractor" , e .extractor )
@@ -706,10 +716,82 @@ func (e *memtableRetriever) setDataFromTables(ctx context.Context, sctx sessionc
706
716
return nil
707
717
}
708
718
719
+ // Special optimize for queries on infoschema v2 like:
720
+ // select count(table_schema) from INFORMATION_SCHEMA.TABLES
721
+ // select count(*) from INFORMATION_SCHEMA.TABLES
722
+ // select table_schema, table_name from INFORMATION_SCHEMA.TABLES
723
+ // column pruning in general is not supported here.
724
+ if onlySchemaOrTableColumns (e .columns ) {
725
+ is := e .is
726
+ if raw , ok := is .(* infoschema.SessionExtendedInfoSchema ); ok {
727
+ is = raw .InfoSchema
728
+ }
729
+ v2 , ok := is .(interface {
730
+ IterateAllTableItems (visit func (infoschema.TableItem ) bool )
731
+ })
732
+ if ok {
733
+ if x := ctx .Value ("cover-check" ); x != nil {
734
+ // The interface assertion is too tricky, so we add test to cover here.
735
+ // To ensure that if implementation changes one day, we can catch it.
736
+ slot := x .(* bool )
737
+ * slot = true
738
+ }
739
+ v2 .IterateAllTableItems (func (t infoschema.TableItem ) bool {
740
+ if ! ex .HasTableName (t .TableName .L ) {
741
+ return true
742
+ }
743
+ if ! ex .HasTableSchema (t .DBName .L ) {
744
+ return true
745
+ }
746
+ if checker != nil && ! checker .RequestVerification (sctx .GetSessionVars ().ActiveRoles , t .DBName .L , t .TableName .L , "" , mysql .SelectPriv ) {
747
+ return true
748
+ }
749
+
750
+ record := types .MakeDatums (
751
+ infoschema .CatalogVal , // TABLE_CATALOG
752
+ t .DBName .O , // TABLE_SCHEMA
753
+ t .TableName .O , // TABLE_NAME
754
+ nil , // TABLE_TYPE
755
+ nil , // ENGINE
756
+ nil , // VERSION
757
+ nil , // ROW_FORMAT
758
+ nil , // TABLE_ROWS
759
+ nil , // AVG_ROW_LENGTH
760
+ nil , // DATA_LENGTH
761
+ nil , // MAX_DATA_LENGTH
762
+ nil , // INDEX_LENGTH
763
+ nil , // DATA_FREE
764
+ nil , // AUTO_INCREMENT
765
+ nil , // CREATE_TIME
766
+ nil , // UPDATE_TIME
767
+ nil , // CHECK_TIME
768
+ nil , // TABLE_COLLATION
769
+ nil , // CHECKSUM
770
+ nil , // CREATE_OPTIONS
771
+ nil , // TABLE_COMMENT
772
+ nil , // TIDB_TABLE_ID
773
+ nil , // TIDB_ROW_ID_SHARDING_INFO
774
+ nil , // TIDB_PK_TYPE
775
+ nil , // TIDB_PLACEMENT_POLICY_NAME
776
+ )
777
+ rows = append (rows , record )
778
+ return true
779
+ })
780
+ e .rows = rows
781
+ return nil
782
+ }
783
+ }
784
+
785
+ // Normal code path.
709
786
schemas , tables , err := ex .ListSchemasAndTables (ctx , e .is )
710
787
if err != nil {
711
788
return errors .Trace (err )
712
789
}
790
+ useStatsCache := e .updateStatsCacheIfNeed ()
791
+ loc := sctx .GetSessionVars ().TimeZone
792
+ if loc == nil {
793
+ loc = time .Local
794
+ }
713
795
for i , table := range tables {
714
796
rows , err = e .setDataFromOneTable (sctx , loc , checker , schemas [i ], table , rows , useStatsCache )
715
797
if err != nil {
0 commit comments