vitess.io/vitess@v0.16.2/go/mysql/endtoend/query_benchmark_test.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 endtoend
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  	"os"
    23  	"sync"
    24  	"testing"
    25  	"time"
    26  
    27  	"github.com/stretchr/testify/require"
    28  
    29  	"vitess.io/vitess/go/mysql"
    30  	vttestpb "vitess.io/vitess/go/vt/proto/vttest"
    31  	"vitess.io/vitess/go/vt/vttest"
    32  )
    33  
    34  // This file contains various long-running tests for mysql.
    35  
    36  // BenchmarkWithRealDatabase runs a real MySQL database, and runs all kinds
    37  // of benchmarks on it. To minimize overhead, we only run one database, and
    38  // run all the benchmarks on it.
    39  func BenchmarkWithRealDatabase(b *testing.B) {
    40  	// Launch MySQL.
    41  	// We need a Keyspace in the topology, so the DbName is set.
    42  	// We need a Shard too, so the database 'vttest' is created.
    43  	cfg := vttest.Config{
    44  		Topology: &vttestpb.VTTestTopology{
    45  			Keyspaces: []*vttestpb.Keyspace{
    46  				{
    47  					Name: "vttest",
    48  					Shards: []*vttestpb.Shard{
    49  						{
    50  							Name:           "0",
    51  							DbNameOverride: "vttest",
    52  						},
    53  					},
    54  				},
    55  			},
    56  		},
    57  		OnlyMySQL: true,
    58  	}
    59  	if err := cfg.InitSchemas("vttest", "create table a(id int, name varchar(128), primary key(id))", nil); err != nil {
    60  		b.Fatalf("InitSchemas failed: %v\n", err)
    61  	}
    62  	defer os.RemoveAll(cfg.SchemaDir)
    63  	cluster := vttest.LocalCluster{
    64  		Config: cfg,
    65  	}
    66  	if err := cluster.Setup(); err != nil {
    67  		b.Fatalf("could not launch mysql: %v\n", err)
    68  	}
    69  	defer cluster.TearDown()
    70  	params := cluster.MySQLConnParams()
    71  
    72  	b.Run("Inserts", func(b *testing.B) {
    73  		benchmarkInserts(b, &params)
    74  	})
    75  	b.Run("ParallelReads", func(b *testing.B) {
    76  		benchmarkParallelReads(b, &params, 10)
    77  	})
    78  }
    79  
    80  func benchmarkInserts(b *testing.B, params *mysql.ConnParams) {
    81  	// Connect.
    82  	ctx := context.Background()
    83  	conn, err := mysql.Connect(ctx, params)
    84  	if err != nil {
    85  		b.Fatal(err)
    86  	}
    87  	defer conn.Close()
    88  
    89  	// Delete what we may already have in the database.
    90  	if _, err := conn.ExecuteFetch("delete from a", 0, false); err != nil {
    91  		b.Fatalf("delete failed: %v", err)
    92  	}
    93  
    94  	// Now reset timer.
    95  	b.ResetTimer()
    96  
    97  	// Do the insert.
    98  	for i := 0; i < b.N; i++ {
    99  		_, err := conn.ExecuteFetch(fmt.Sprintf("insert into a(id, name) values(%v, 'nice name %v')", i, i), 0, false)
   100  		if err != nil {
   101  			b.Fatalf("ExecuteFetch(%v) failed: %v", i, err)
   102  		}
   103  	}
   104  }
   105  
   106  func benchmarkParallelReads(b *testing.B, params *mysql.ConnParams, parallelCount int) {
   107  	ctx := context.Background()
   108  	wg := sync.WaitGroup{}
   109  	for i := 0; i < parallelCount; i++ {
   110  		wg.Add(1)
   111  		go func(i int) {
   112  			defer wg.Done()
   113  
   114  			conn, err := mysql.Connect(ctx, params)
   115  			if err != nil {
   116  				b.Error(err)
   117  			}
   118  
   119  			for j := 0; j < b.N; j++ {
   120  				if _, err := conn.ExecuteFetch("select * from a", 20000, true); err != nil {
   121  					b.Errorf("ExecuteFetch(%v, %v) failed: %v", i, j, err)
   122  				}
   123  			}
   124  			conn.Close()
   125  		}(i)
   126  	}
   127  	wg.Wait()
   128  }
   129  
   130  func BenchmarkSetVarsWithQueryHints(b *testing.B) {
   131  	ctx := context.Background()
   132  	conn, err := mysql.Connect(ctx, &connParams)
   133  	if err != nil {
   134  		b.Fatal(err)
   135  	}
   136  
   137  	_, err = conn.ExecuteFetch("create table t(id int primary key, name varchar(100))", 1, false)
   138  	require.NoError(b, err)
   139  
   140  	defer func() {
   141  		_, err = conn.ExecuteFetch("drop table t", 1, false)
   142  		require.NoError(b, err)
   143  	}()
   144  
   145  	for _, sleepDuration := range []time.Duration{0, 1 * time.Millisecond} {
   146  		b.Run(fmt.Sprintf("Sleep %d ms", sleepDuration/time.Millisecond), func(b *testing.B) {
   147  			for i := 0; i < b.N; i++ {
   148  				_, err := conn.ExecuteFetch(fmt.Sprintf("insert /*+ SET_VAR(sql_mode = ' ') SET_VAR(sql_safe_updates = 0) */ into t(id) values (%d)", i), 1, false)
   149  				if err != nil {
   150  					b.Fatal(err)
   151  				}
   152  
   153  				_, err = conn.ExecuteFetch(fmt.Sprintf("select /*+ SET_VAR(sql_mode = ' ') SET_VAR(sql_safe_updates = 0) */ * from t where id = %d", i), 1, false)
   154  				if err != nil {
   155  					b.Fatal(err)
   156  				}
   157  
   158  				_, err = conn.ExecuteFetch(fmt.Sprintf("update /*+ SET_VAR(sql_mode = ' ') SET_VAR(sql_safe_updates = 0) */ t set name = 'foo' where id = %d", i), 1, false)
   159  				if err != nil {
   160  					b.Fatal(err)
   161  				}
   162  
   163  				_, err = conn.ExecuteFetch(fmt.Sprintf("delete /*+ SET_VAR(sql_mode = ' ') SET_VAR(sql_safe_updates = 0) */ from t where id = %d", i), 1, false)
   164  				if err != nil {
   165  					b.Fatal(err)
   166  				}
   167  				time.Sleep(sleepDuration)
   168  			}
   169  		})
   170  	}
   171  }
   172  
   173  func BenchmarkSetVarsMultipleSets(b *testing.B) {
   174  	ctx := context.Background()
   175  	conn, err := mysql.Connect(ctx, &connParams)
   176  	if err != nil {
   177  		b.Fatal(err)
   178  	}
   179  
   180  	_, err = conn.ExecuteFetch("create table t(id int primary key, name varchar(100))", 1, false)
   181  	require.NoError(b, err)
   182  
   183  	defer func() {
   184  		_, err = conn.ExecuteFetch("drop table t", 1, false)
   185  		require.NoError(b, err)
   186  	}()
   187  
   188  	setFunc := func() {
   189  		_, err = conn.ExecuteFetch("set sql_mode = '', sql_safe_updates = 0;", 1, false)
   190  		if err != nil {
   191  			b.Fatal(err)
   192  		}
   193  	}
   194  
   195  	for _, sleepDuration := range []time.Duration{0, 1 * time.Millisecond} {
   196  		b.Run(fmt.Sprintf("Sleep %d ms", sleepDuration/time.Millisecond), func(b *testing.B) {
   197  			for i := 0; i < b.N; i++ {
   198  				setFunc()
   199  
   200  				_, err = conn.ExecuteFetch(fmt.Sprintf("insert into t(id) values (%d)", i), 1, false)
   201  				if err != nil {
   202  					b.Fatal(err)
   203  				}
   204  				setFunc()
   205  
   206  				_, err = conn.ExecuteFetch(fmt.Sprintf("select * from t where id = %d", i), 1, false)
   207  				if err != nil {
   208  					b.Fatal(err)
   209  				}
   210  				setFunc()
   211  
   212  				_, err = conn.ExecuteFetch(fmt.Sprintf("update t set name = 'foo' where id = %d", i), 1, false)
   213  				if err != nil {
   214  					b.Fatal(err)
   215  				}
   216  				setFunc()
   217  
   218  				_, err = conn.ExecuteFetch(fmt.Sprintf("delete from t where id = %d", i), 1, false)
   219  				if err != nil {
   220  					b.Fatal(err)
   221  				}
   222  				time.Sleep(sleepDuration)
   223  			}
   224  		})
   225  	}
   226  }
   227  
   228  func BenchmarkSetVarsMultipleSetsInSameStmt(b *testing.B) {
   229  	ctx := context.Background()
   230  	conn, err := mysql.Connect(ctx, &connParams)
   231  	if err != nil {
   232  		b.Fatal(err)
   233  	}
   234  
   235  	_, err = conn.ExecuteFetch("create table t(id int primary key, name varchar(100))", 1, false)
   236  	require.NoError(b, err)
   237  
   238  	defer func() {
   239  		_, err = conn.ExecuteFetch("drop table t", 1, false)
   240  		require.NoError(b, err)
   241  	}()
   242  
   243  	for _, sleepDuration := range []time.Duration{0, 1 * time.Millisecond} {
   244  		b.Run(fmt.Sprintf("Sleep %d ms", sleepDuration/time.Millisecond), func(b *testing.B) {
   245  			for i := 0; i < b.N; i++ {
   246  				_, _, err := conn.ExecuteFetchMulti(fmt.Sprintf("set sql_mode = '', sql_safe_updates = 0 ; insert into t(id) values (%d)", i), 1, false)
   247  				if err != nil {
   248  					b.Fatal(err)
   249  				}
   250  				_, _, _, err = conn.ReadQueryResult(1, false)
   251  				if err != nil {
   252  					b.Fatal(err)
   253  				}
   254  
   255  				_, _, err = conn.ExecuteFetchMulti(fmt.Sprintf("set sql_mode = '', sql_safe_updates = 0 ; select * from t where id = %d", i), 1, false)
   256  				if err != nil {
   257  					b.Fatal(err)
   258  				}
   259  				_, _, _, err = conn.ReadQueryResult(1, false)
   260  				if err != nil {
   261  					b.Fatal(err)
   262  				}
   263  
   264  				_, _, err = conn.ExecuteFetchMulti(fmt.Sprintf("set sql_mode = '', sql_safe_updates = 0 ; update t set name = 'foo' where id = %d", i), 1, false)
   265  				if err != nil {
   266  					b.Fatal(err)
   267  				}
   268  				_, _, _, err = conn.ReadQueryResult(1, false)
   269  				if err != nil {
   270  					b.Fatal(err)
   271  				}
   272  
   273  				_, _, err = conn.ExecuteFetchMulti(fmt.Sprintf("set sql_mode = '', sql_safe_updates = 0 ; delete from t where id = %d", i), 1, false)
   274  				if err != nil {
   275  					b.Fatal(err)
   276  				}
   277  				_, _, _, err = conn.ReadQueryResult(1, false)
   278  				if err != nil {
   279  					b.Fatal(err)
   280  				}
   281  				time.Sleep(sleepDuration)
   282  			}
   283  		})
   284  	}
   285  }
   286  
   287  func BenchmarkSetVarsSingleSet(b *testing.B) {
   288  	ctx := context.Background()
   289  	conn, err := mysql.Connect(ctx, &connParams)
   290  	if err != nil {
   291  		b.Fatal(err)
   292  	}
   293  
   294  	_, err = conn.ExecuteFetch("set sql_mode = '', sql_safe_updates = 0", 1, false)
   295  	require.NoError(b, err)
   296  
   297  	_, err = conn.ExecuteFetch("create table t(id int primary key, name varchar(100))", 1, false)
   298  	require.NoError(b, err)
   299  
   300  	defer func() {
   301  		_, err = conn.ExecuteFetch("drop table t", 1, false)
   302  		require.NoError(b, err)
   303  	}()
   304  
   305  	for _, sleepDuration := range []time.Duration{0, 1 * time.Millisecond} {
   306  		b.Run(fmt.Sprintf("Sleep %d ms", sleepDuration/time.Millisecond), func(b *testing.B) {
   307  			for i := 0; i < b.N; i++ {
   308  				_, err = conn.ExecuteFetch(fmt.Sprintf("insert into t(id) values (%d)", i), 1, false)
   309  				if err != nil {
   310  					b.Fatal(err)
   311  				}
   312  
   313  				_, err = conn.ExecuteFetch(fmt.Sprintf("select * from t where id = %d", i), 1, false)
   314  				if err != nil {
   315  					b.Fatal(err)
   316  				}
   317  
   318  				_, err = conn.ExecuteFetch(fmt.Sprintf("update t set name = 'foo' where id = %d", i), 1, false)
   319  				if err != nil {
   320  					b.Fatal(err)
   321  				}
   322  
   323  				_, err = conn.ExecuteFetch(fmt.Sprintf("delete from t where id = %d", i), 1, false)
   324  				if err != nil {
   325  					b.Fatal(err)
   326  				}
   327  				time.Sleep(sleepDuration)
   328  			}
   329  		})
   330  	}
   331  
   332  }