github.com/matrixorigin/matrixone@v1.2.0/pkg/util/trace/impl/motrace/schema.go (about)

     1  // Copyright 2022 Matrix Origin
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package motrace
    16  
    17  import (
    18  	"context"
    19  	"fmt"
    20  	"time"
    21  
    22  	"github.com/matrixorigin/matrixone/pkg/catalog"
    23  	"github.com/matrixorigin/matrixone/pkg/util/trace/impl/motrace/statistic"
    24  
    25  	"github.com/matrixorigin/matrixone/pkg/util/export/table"
    26  
    27  	"github.com/matrixorigin/matrixone/pkg/common/moerr"
    28  	"github.com/matrixorigin/matrixone/pkg/logutil"
    29  	ie "github.com/matrixorigin/matrixone/pkg/util/internalExecutor"
    30  )
    31  
    32  const (
    33  	SystemDBConst = "system"
    34  	StatsDatabase = SystemDBConst
    35  )
    36  const (
    37  	// statementInfoTbl is an EXTERNAL table
    38  	statementInfoTbl = "statement_info"
    39  	RawLogTbl        = "rawlog"
    40  
    41  	// spanInfoTbl is a view
    42  	spanInfoTbl  = "span_info"
    43  	logInfoTbl   = "log_info"
    44  	errorInfoTbl = "error_info"
    45  
    46  	SqlStatementHotspotTbl = "sql_statement_hotspot"
    47  )
    48  
    49  var (
    50  	stmtIDCol    = table.UuidStringColumn("statement_id", "statement uniq id")
    51  	txnIDCol     = table.UuidStringColumn("transaction_id", "txn uniq id")
    52  	sesIDCol     = table.UuidStringColumn("session_id", "session uniq id")
    53  	accountCol   = table.StringColumn("account", "account name")
    54  	roleIdCol    = table.Int64Column("role_id", "role id")
    55  	userCol      = table.StringColumn("user", "user name")
    56  	hostCol      = table.StringColumn("host", "user client ip")
    57  	dbCol        = table.StringColumn("database", "what database current session stay in.")
    58  	stmtCol      = table.TextColumn("statement", "sql statement")
    59  	stmtTagCol   = table.TextColumn("statement_tag", "note tag in statement(Reserved)")
    60  	stmtFgCol    = table.TextColumn("statement_fingerprint", "note tag in statement(Reserved)")
    61  	nodeUUIDCol  = table.UuidStringColumn("node_uuid", "node uuid, which node gen this data.")
    62  	nodeTypeCol  = table.StringColumn("node_type", "node type in MO, val in [DN, CN, LOG]")
    63  	reqAtCol     = table.DatetimeColumn("request_at", "request accept datetime")
    64  	respAtCol    = table.DatetimeColumn("response_at", "response send datetime")
    65  	durationCol  = table.UInt64Column("duration", "exec time, unit: ns")
    66  	statusCol    = table.StringColumn("status", "sql statement running status, enum: Running, Success, Failed")
    67  	errorCol     = table.TextColumn("error", "error message")
    68  	execPlanCol  = table.TextDefaultColumn("exec_plan", `{}`, "statement execution plan")
    69  	rowsReadCol  = table.Int64Column("rows_read", "rows read total")
    70  	bytesScanCol = table.Int64Column("bytes_scan", "bytes scan total")
    71  	statsCol     = table.TextDefaultColumn("stats", `[]`, "global stats info in exec_plan")
    72  	stmtTypeCol  = table.StringColumn("statement_type", "statement type, val in [Insert, Delete, Update, Drop Table, Drop User, ...]")
    73  	queryTypeCol = table.StringColumn("query_type", "query type, val in [DQL, DDL, DML, DCL, TCL]")
    74  	sqlTypeCol   = table.TextColumn("sql_source_type", "sql statement source type")
    75  	aggrCntCol   = table.Int64Column("aggr_count", "the number of statements aggregated")
    76  	resultCntCol = table.Int64Column("result_count", "the number of rows of sql execution results")
    77  
    78  	SingleStatementTable = &table.Table{
    79  		Account:  table.AccountSys,
    80  		Database: StatsDatabase,
    81  		Table:    statementInfoTbl,
    82  		Columns: []table.Column{
    83  			stmtIDCol,
    84  			txnIDCol,
    85  			sesIDCol,
    86  			accountCol,
    87  			userCol,
    88  			hostCol,
    89  			dbCol,
    90  			stmtCol,
    91  			stmtTagCol,
    92  			stmtFgCol,
    93  			nodeUUIDCol,
    94  			nodeTypeCol,
    95  			reqAtCol,
    96  			respAtCol,
    97  			durationCol,
    98  			statusCol,
    99  			errCodeCol,
   100  			errorCol,
   101  			execPlanCol,
   102  			rowsReadCol,
   103  			bytesScanCol,
   104  			statsCol,
   105  			stmtTypeCol,
   106  			queryTypeCol,
   107  			roleIdCol,
   108  			sqlTypeCol,
   109  			aggrCntCol,
   110  			resultCntCol,
   111  		},
   112  		PrimaryKeyColumn: nil,
   113  		ClusterBy:        []table.Column{reqAtCol},
   114  		// Engine
   115  		Engine:        table.NormalTableEngine,
   116  		Comment:       "record each statement and stats info" + catalog.MO_COMMENT_NO_DEL_HINT,
   117  		PathBuilder:   table.NewAccountDatePathBuilder(),
   118  		AccountColumn: &accountCol,
   119  		// TimestampColumn
   120  		TimestampColumn: &respAtCol,
   121  		// SupportUserAccess
   122  		SupportUserAccess: true,
   123  		// SupportConstAccess
   124  		SupportConstAccess: true,
   125  	}
   126  
   127  	rawItemCol      = table.StringColumn("raw_item", "raw log item")
   128  	timestampCol    = table.DatetimeColumn("timestamp", "timestamp of action")
   129  	loggerNameCol   = table.StringColumn("logger_name", "logger name")
   130  	levelCol        = table.StringColumn("level", "log level, enum: debug, info, warn, error, panic, fatal")
   131  	callerCol       = table.StringColumn("caller", "where it log, like: package/file.go:123")
   132  	messageCol      = table.TextColumn("message", "log message")
   133  	extraCol        = table.TextDefaultColumn("extra", `{}`, "log dynamic fields")
   134  	errCodeCol      = table.StringDefaultColumn("err_code", `0`, "error code info")
   135  	stackCol        = table.StringWithScale("stack", 2048, "stack info")
   136  	traceIDCol      = table.UuidStringColumn("trace_id", "trace uniq id")
   137  	spanIDCol       = table.SpanIDStringColumn("span_id", "span uniq id")
   138  	sessionIDCol    = table.UuidStringColumn("session_id", "session id")
   139  	statementIDCol  = table.UuidStringColumn("statement_id", "statement id")
   140  	spanKindCol     = table.StringColumn("span_kind", "span kind, enum: internal, statement, remote")
   141  	parentSpanIDCol = table.SpanIDStringColumn("parent_span_id", "parent span uniq id")
   142  	spanNameCol     = table.StringColumn("span_name", "span name, for example: step name of execution plan, function name in code, ...")
   143  	startTimeCol    = table.DatetimeColumn("start_time", "start time")
   144  	endTimeCol      = table.DatetimeColumn("end_time", "end time")
   145  	resourceCol     = table.TextDefaultColumn("resource", `{}`, "static resource information")
   146  
   147  	UpgradeColumns = map[string]map[string][]table.Column{
   148  		"1.0": {
   149  			"ADD": {
   150  				statementIDCol,
   151  				sessionIDCol,
   152  			},
   153  		},
   154  	}
   155  
   156  	SingleRowLogTable = &table.Table{
   157  		Account:  table.AccountSys,
   158  		Database: StatsDatabase,
   159  		Table:    RawLogTbl,
   160  		Columns: []table.Column{
   161  			rawItemCol,
   162  			nodeUUIDCol,
   163  			nodeTypeCol,
   164  			spanIDCol,
   165  			traceIDCol,
   166  			loggerNameCol,
   167  			timestampCol,
   168  			levelCol,
   169  			callerCol,
   170  			messageCol,
   171  			extraCol,
   172  			errCodeCol,
   173  			errorCol,
   174  			stackCol,
   175  			spanNameCol,
   176  			parentSpanIDCol,
   177  			startTimeCol,
   178  			endTimeCol,
   179  			durationCol,
   180  			resourceCol,
   181  			spanKindCol,
   182  			statementIDCol,
   183  			sessionIDCol,
   184  		},
   185  		PrimaryKeyColumn: nil,
   186  		ClusterBy:        []table.Column{timestampCol},
   187  		Engine:           table.NormalTableEngine,
   188  		Comment:          "read merge data from log, error, span" + catalog.MO_COMMENT_NO_DEL_HINT,
   189  		PathBuilder:      table.NewAccountDatePathBuilder(),
   190  		AccountColumn:    nil,
   191  		// TimestampColumn
   192  		TimestampColumn: &timestampCol,
   193  		// SupportUserAccess
   194  		SupportUserAccess: false,
   195  		// SupportConstAccess
   196  		SupportConstAccess: true,
   197  	}
   198  
   199  	logView = &table.View{
   200  		Database:    StatsDatabase,
   201  		Table:       logInfoTbl,
   202  		OriginTable: SingleRowLogTable,
   203  		Columns: []table.Column{
   204  			traceIDCol,
   205  			spanIDCol,
   206  			spanKindCol,
   207  			nodeUUIDCol,
   208  			nodeTypeCol,
   209  			timestampCol,
   210  			loggerNameCol,
   211  			levelCol,
   212  			callerCol,
   213  			messageCol,
   214  			extraCol,
   215  			stackCol,
   216  		},
   217  		Condition: &table.ViewSingleCondition{Column: rawItemCol, Table: logInfoTbl},
   218  	}
   219  
   220  	errorView = &table.View{
   221  		Database:    StatsDatabase,
   222  		Table:       errorInfoTbl,
   223  		OriginTable: SingleRowLogTable,
   224  		Columns: []table.Column{
   225  			timestampCol,
   226  			errCodeCol,
   227  			errorCol,
   228  			traceIDCol,
   229  			spanIDCol,
   230  			spanKindCol,
   231  			nodeUUIDCol,
   232  			nodeTypeCol,
   233  			stackCol,
   234  		},
   235  		Condition: &table.ViewSingleCondition{Column: rawItemCol, Table: errorInfoTbl},
   236  	}
   237  
   238  	spanView = &table.View{
   239  		Database:    StatsDatabase,
   240  		Table:       spanInfoTbl,
   241  		OriginTable: SingleRowLogTable,
   242  		Columns: []table.Column{
   243  			traceIDCol,
   244  			spanIDCol,
   245  			parentSpanIDCol,
   246  			spanKindCol,
   247  			nodeUUIDCol,
   248  			nodeTypeCol,
   249  			spanNameCol,
   250  			startTimeCol,
   251  			endTimeCol,
   252  			durationCol,
   253  			resourceCol,
   254  			extraCol,
   255  		},
   256  		Condition: &table.ViewSingleCondition{Column: rawItemCol, Table: spanInfoTbl},
   257  	}
   258  
   259  	SqlStatementHotspotView = &table.View{
   260  		Database:    StatsDatabase,
   261  		Table:       SqlStatementHotspotTbl,
   262  		OriginTable: SingleStatementTable,
   263  		Columns: []table.Column{
   264  			table.StringColumn("statement_id", "the statement's uuid"),
   265  			table.StringColumn("statement", "query's statement"),
   266  			table.ValueColumn("timeconsumed", "query's exec time (unit: ms)"),
   267  			table.ValueColumn("memorysize", "query's consume mem size (unit: MiB)"),
   268  			table.DatetimeColumn("collecttime", "collected time, same as query's response time"),
   269  			table.StringColumn("node", "cn node uuid"),
   270  			table.StringColumn("account", "account id "),
   271  			table.StringColumn("user", "user name"),
   272  			table.StringColumn("type", "statement type, like: [Insert, Delete, Update, Select, ...]"),
   273  		},
   274  		CreateSql: table.ViewCreateSqlString(fmt.Sprintf(`CREATE VIEW IF NOT EXISTS system.sql_statement_hotspot AS
   275  select statement_id, statement, duration / 1e6 as timeconsumed,
   276  cast(json_unquote(json_extract(stats, '$[%d]')) / 1048576.00 as decimal(38,3)) as memorysize,
   277  response_at as collecttime,
   278  node_uuid as node,
   279  account,
   280  user,
   281  statement_type as type
   282   from system.statement_info
   283   where response_at > date_sub(now(), interval 10 minute) and response_at < now()
   284  and aggr_count = 0 order by duration desc limit 10;`, statistic.StatsArrayIndexMemorySize)),
   285  		SupportUserAccess: false,
   286  	}
   287  )
   288  
   289  const (
   290  	sqlCreateDBConst = `create database if not exists ` + StatsDatabase
   291  )
   292  
   293  var tables = []*table.Table{SingleStatementTable, SingleRowLogTable}
   294  var views = []*table.View{logView, errorView, spanView, SqlStatementHotspotView}
   295  
   296  // InitSchemaByInnerExecutor init schema, which can access db by io.InternalExecutor on any Node.
   297  func InitSchemaByInnerExecutor(ctx context.Context, ieFactory func() ie.InternalExecutor) error {
   298  	exec := ieFactory()
   299  	if exec == nil {
   300  		return nil
   301  	}
   302  	exec.ApplySessionOverride(ie.NewOptsBuilder().Database(StatsDatabase).Internal(true).Finish())
   303  	mustExec := func(sql string) error {
   304  		if err := exec.Exec(ctx, sql, ie.NewOptsBuilder().Finish()); err != nil {
   305  			return moerr.NewInternalError(ctx, "[Trace] init table error: %v, sql: %s", err, sql)
   306  		}
   307  		return nil
   308  	}
   309  
   310  	if err := mustExec(sqlCreateDBConst); err != nil {
   311  		return err
   312  	}
   313  	var createCost time.Duration
   314  	defer func() {
   315  		logutil.Debugf("[Trace] init tables: create cost %d ms",
   316  			createCost.Milliseconds())
   317  	}()
   318  	instant := time.Now()
   319  
   320  	for _, tbl := range tables {
   321  		if err := mustExec(tbl.ToCreateSql(ctx, true)); err != nil {
   322  			return err
   323  		}
   324  	}
   325  	for _, v := range views {
   326  		if err := mustExec(v.ToCreateSql(ctx, true)); err != nil {
   327  			return err
   328  		}
   329  	}
   330  
   331  	createCost = time.Since(instant)
   332  	return nil
   333  }
   334  
   335  // GetAllTables
   336  //
   337  // Deprecated: use table.GetAllTables() instead.
   338  func GetAllTables() []*table.Table {
   339  	return tables
   340  }
   341  
   342  // GetSchemaForAccount return account's table, and view's schema
   343  func GetSchemaForAccount(ctx context.Context, account string) []string {
   344  	var sqls = make([]string, 0, 1)
   345  	for _, tbl := range tables {
   346  		if tbl.SupportUserAccess {
   347  			t := tbl.Clone()
   348  			t.Account = account
   349  			sqls = append(sqls, t.ToCreateSql(ctx, true))
   350  		}
   351  	}
   352  	for _, v := range views {
   353  		if v.SupportUserAccess && v.OriginTable.SupportUserAccess {
   354  			sqls = append(sqls, v.ToCreateSql(ctx, true))
   355  		}
   356  
   357  	}
   358  	return sqls
   359  }
   360  
   361  func init() {
   362  	for _, tbl := range tables {
   363  		tbl.GetRow(context.Background()).Free()
   364  		if old := table.RegisterTableDefine(tbl); old != nil {
   365  			panic(moerr.NewInternalError(context.Background(), "table already registered: %s", old.GetIdentify()))
   366  		}
   367  	}
   368  }