Skip to content

Commit

Permalink
planner: optimize the performance of PlanCacheParamList.String() (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
qw4990 authored Sep 4, 2023
1 parent be5ce3d commit 7a4c566
Show file tree
Hide file tree
Showing 3 changed files with 115 additions and 13 deletions.
2 changes: 1 addition & 1 deletion executor/show_stats_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ func TestShowStatsLocked(t *testing.T) {
tk.MustExec("create table t (a int, b int)")
tk.MustExec("create table t1 (a int, b int)")
tk.MustExec("lock stats t, t1")
result := tk.MustQuery("show stats_locked")
result := tk.MustQuery("show stats_locked").Sort()
require.Len(t, result.Rows(), 2)
require.Equal(t, "t", result.Rows()[0][1])
require.Equal(t, "t1", result.Rows()[1][1])
Expand Down
49 changes: 37 additions & 12 deletions types/datum.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"sort"
"strconv"
"strings"
"sync"
"time"
"unicode/utf8"
"unsafe"
Expand Down Expand Up @@ -2283,39 +2284,63 @@ func (ds *datumsSorter) Swap(i, j int) {
ds.datums[i], ds.datums[j] = ds.datums[j], ds.datums[i]
}

var strBuilderPool = sync.Pool{New: func() interface{} { return &strings.Builder{} }}

// DatumsToString converts several datums to formatted string.
func DatumsToString(datums []Datum, handleSpecialValue bool) (string, error) {
strs := make([]string, 0, len(datums))
for _, datum := range datums {
n := len(datums)
builder := strBuilderPool.Get().(*strings.Builder)
defer func() {
builder.Reset()
strBuilderPool.Put(builder)
}()
if n > 1 {
builder.WriteString("(")
}
for i, datum := range datums {
if i > 0 {
builder.WriteString(", ")
}
if handleSpecialValue {
switch datum.Kind() {
case KindNull:
strs = append(strs, "NULL")
builder.WriteString("NULL")
continue
case KindMinNotNull:
strs = append(strs, "-inf")
builder.WriteString("-inf")
continue
case KindMaxValue:
strs = append(strs, "+inf")
builder.WriteString("+inf")
continue
}
}
str, err := datum.ToString()
if err != nil {
return "", errors.Trace(err)
}
const logDatumLen = 2048
originalLen := -1
if len(str) > logDatumLen {
originalLen = len(str)
str = str[:logDatumLen]
}
if datum.Kind() == KindString {
strs = append(strs, fmt.Sprintf("%q", str))
builder.WriteString(`"`)
builder.WriteString(str)
builder.WriteString(`"`)
} else {
strs = append(strs, str)
builder.WriteString(str)
}
if originalLen != -1 {
builder.WriteString(" len(")
builder.WriteString(strconv.Itoa(originalLen))
builder.WriteString(")")
}
}
size := len(datums)
if size > 1 {
strs[0] = "(" + strs[0]
strs[size-1] = strs[size-1] + ")"
if n > 1 {
builder.WriteString(")")
}
return strings.Join(strs, ", "), nil
return builder.String(), nil
}

// DatumsToStrNoErr converts some datums to a formatted string.
Expand Down
77 changes: 77 additions & 0 deletions types/datum_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"math"
"reflect"
"strconv"
"strings"
"testing"
"time"

Expand Down Expand Up @@ -704,3 +705,79 @@ func TestNULLNotEqualWithOthers(t *testing.T) {
require.NotEqual(t, 0, result)
}
}

func TestDatumsToString(t *testing.T) {
datums := []Datum{
NewIntDatum(1),
NewUintDatum(2),
NewFloat32Datum(-3.1111111),
NewFloat64Datum(4.123),
NewDatum(math.Inf(5)),
NewDecimalDatum(NewDecFromStringForTest("6.6")),
NewStringDatum("abc"),
NewCollationStringDatum("", charset.CollationBin),
NewDurationDatum(Duration{Duration: time.Duration(11111)}),
NewTimeDatum(ZeroTime),
NewBytesDatum([]byte("xxx")),
NewBinaryLiteralDatum([]byte{}),
NewJSONDatum(CreateBinaryJSON(nil)),
MinNotNullDatum(),
MaxValueDatum(),
}
str, err := DatumsToString(datums, true)
require.NoError(t, err)
require.Equal(t, str, `(1, 2, -3.1111112, 4.123, +Inf, 6.6, "abc", "", 00:00:00, 0000-00-00 00:00:00, xxx, , null, -inf, +inf)`)
}

func BenchmarkDatumsToString(b *testing.B) {
datums := []Datum{
NewIntDatum(1),
NewUintDatum(2),
NewFloat32Datum(-3.1111111),
NewFloat64Datum(4.123),
NewDatum(math.Inf(5)),
NewDecimalDatum(NewDecFromStringForTest("6.66666")),
NewStringDatum("dklsfjkaslnfwoiewlkfjaslkfjljs"),
NewCollationStringDatum("1234567890-=12345656789", charset.CollationBin),
NewDurationDatum(Duration{Duration: time.Duration(11111)}),
NewTimeDatum(ZeroTime),
NewBytesDatum([]byte("xxxxxxxxxxxxxxxxxxxxxxx")),
NewBinaryLiteralDatum([]byte{}),
NewJSONDatum(CreateBinaryJSON(nil)),
MinNotNullDatum(),
MaxValueDatum(),
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, err := DatumsToString(datums, true)
if err != nil {
b.Fatal(err)
}
}
}

func BenchmarkDatumsToStringStr(b *testing.B) {
datums := []Datum{
NewStringDatum(strings.Repeat("1", 512)),
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, err := DatumsToString(datums, true)
if err != nil {
b.Fatal(err)
}
}
}

func BenchmarkDatumsToStringLongStr(b *testing.B) {
datums := []Datum{
NewStringDatum(strings.Repeat("1", 1024*10)), // 10KB
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, err := DatumsToString(datums, true)
if err != nil {
b.Fatal(err)
}
}
}

0 comments on commit 7a4c566

Please sign in to comment.