vitess.io/vitess@v0.16.2/go/cmd/query_analyzer/query_analyzer.go (about)

     1  /*
     2  Copyright 2019 The Vitess Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package main
    18  
    19  import (
    20  	"bufio"
    21  	"bytes"
    22  	"fmt"
    23  	"io"
    24  	"os"
    25  	"sort"
    26  
    27  	"github.com/spf13/pflag"
    28  
    29  	"vitess.io/vitess/go/acl"
    30  	"vitess.io/vitess/go/exit"
    31  	"vitess.io/vitess/go/vt/log"
    32  	"vitess.io/vitess/go/vt/logutil"
    33  	"vitess.io/vitess/go/vt/servenv"
    34  	"vitess.io/vitess/go/vt/sqlparser"
    35  
    36  	// Include deprecation warnings for soon-to-be-unsupported flag invocations.
    37  	_flag "vitess.io/vitess/go/internal/flag"
    38  )
    39  
    40  var (
    41  	ignores = [][]byte{
    42  		[]byte("#"),
    43  		[]byte("/*"),
    44  		[]byte("SET"),
    45  		[]byte("use"),
    46  		[]byte("BEGIN"),
    47  		[]byte("COMMIT"),
    48  		[]byte("ROLLBACK"),
    49  	}
    50  	bindIndex = 0
    51  	queries   = make(map[string]int)
    52  )
    53  
    54  type stat struct {
    55  	Query string
    56  	Count int
    57  }
    58  
    59  type stats []stat
    60  
    61  func (a stats) Len() int           { return len(a) }
    62  func (a stats) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
    63  func (a stats) Less(i, j int) bool { return a[i].Count > a[j].Count }
    64  
    65  func main() {
    66  	defer exit.Recover()
    67  	fs := pflag.NewFlagSet("query_analyzer", pflag.ExitOnError)
    68  	log.RegisterFlags(fs)
    69  	logutil.RegisterFlags(fs)
    70  	acl.RegisterFlags(fs)
    71  	servenv.RegisterMySQLServerFlags(fs)
    72  	_flag.Parse(fs)
    73  	logutil.PurgeLogs()
    74  	for _, filename := range _flag.Args() {
    75  		fmt.Printf("processing: %s\n", filename)
    76  		if err := processFile(filename); err != nil {
    77  			log.Errorf("processFile error: %v", err)
    78  			exit.Return(1)
    79  		}
    80  	}
    81  	var stats = make(stats, 0, 128)
    82  	for k, v := range queries {
    83  		stats = append(stats, stat{Query: k, Count: v})
    84  	}
    85  	sort.Sort(stats)
    86  	for _, s := range stats {
    87  		fmt.Printf("%d: %s\n", s.Count, s.Query)
    88  	}
    89  }
    90  
    91  func processFile(filename string) error {
    92  	f, err := os.Open(filename)
    93  	if err != nil {
    94  		return err
    95  	}
    96  	r := bufio.NewReader(f)
    97  	for {
    98  		line, err := r.ReadBytes('\n')
    99  		if err != nil {
   100  			if err == io.EOF {
   101  				break
   102  			}
   103  			return err
   104  		}
   105  		analyze(line)
   106  	}
   107  	return nil
   108  }
   109  
   110  func analyze(line []byte) {
   111  	for _, ignore := range ignores {
   112  		if bytes.HasPrefix(line, ignore) {
   113  			return
   114  		}
   115  	}
   116  	dml := string(bytes.TrimRight(line, "\n"))
   117  	ast, err := sqlparser.Parse(dml)
   118  	if err != nil {
   119  		log.Errorf("Error parsing %s", dml)
   120  		return
   121  	}
   122  	bindIndex = 0
   123  	buf := sqlparser.NewTrackedBuffer(formatWithBind)
   124  	buf.Myprintf("%v", ast)
   125  	addQuery(buf.ParsedQuery().Query)
   126  }
   127  
   128  func formatWithBind(buf *sqlparser.TrackedBuffer, node sqlparser.SQLNode) {
   129  	v, ok := node.(*sqlparser.Literal)
   130  	if !ok {
   131  		node.Format(buf)
   132  		return
   133  	}
   134  	switch v.Type {
   135  	case sqlparser.StrVal, sqlparser.HexVal, sqlparser.IntVal:
   136  		buf.WriteArg(":", fmt.Sprintf("v%d", bindIndex))
   137  		bindIndex++
   138  	default:
   139  		node.Format(buf)
   140  	}
   141  }
   142  
   143  func addQuery(query string) {
   144  	count, ok := queries[query]
   145  	if !ok {
   146  		count = 0
   147  	}
   148  	queries[query] = count + 1
   149  }