codec: improve the performance of decoding decimal (#5921)

This commit is contained in:
Jian Zhang
2018-02-28 20:21:31 +08:00
committed by Yiding Cui
parent fb69fa9a91
commit 45dc066401
6 changed files with 35 additions and 22 deletions

View File

@ -684,10 +684,15 @@ func convertFloat(val []byte, f32 bool) (*Constant, error) {
func convertDecimal(val []byte) (*Constant, error) {
_, dec, err := codec.DecodeDecimal(val)
var d types.Datum
precision, frac := dec.PrecisionAndFrac()
d.SetMysqlDecimal(dec)
d.SetLength(precision)
d.SetFrac(frac)
if err != nil {
return nil, errors.Errorf("invalid decimal % x", val)
}
return &Constant{Value: dec, RetType: types.NewFieldType(mysql.TypeNewDecimal)}, nil
return &Constant{Value: d, RetType: types.NewFieldType(mysql.TypeNewDecimal)}, nil
}
func convertDuration(val []byte) (*Constant, error) {

View File

@ -1235,7 +1235,8 @@ func (d *MyDecimal) FromBin(bin []byte, precision, frac int) (binSize int, err e
mask = 0
}
binSize = decimalBinSize(precision, frac)
dCopy := make([]byte, binSize)
dCopy := make([]byte, 40)
dCopy = dCopy[:binSize]
copy(dCopy, bin)
dCopy[0] ^= 0x80
bin = dCopy

View File

@ -60,3 +60,14 @@ func BenchmarkEncodeIntWithOutSize(b *testing.B) {
EncodeInt(nil, 10)
}
}
func BenchmarkDecodeDecimal(b *testing.B) {
dec := &types.MyDecimal{}
dec.FromFloat64(1211.1211113)
precision, frac := dec.PrecisionAndFrac()
raw := EncodeDecimal([]byte{}, dec, precision, frac)
b.ResetTimer()
for i := 0; i < b.N; i++ {
DecodeDecimal(raw)
}
}

View File

@ -334,7 +334,12 @@ func DecodeOne(b []byte) (remain []byte, d types.Datum, err error) {
b, v, err = DecodeCompactBytes(b)
d.SetBytes(v)
case decimalFlag:
b, d, err = DecodeDecimal(b)
var dec *types.MyDecimal
b, dec, err = DecodeDecimal(b)
precision, frac := dec.PrecisionAndFrac()
d.SetMysqlDecimal(dec)
d.SetLength(precision)
d.SetFrac(frac)
case durationFlag:
var r int64
b, r, err = DecodeInt(b)
@ -534,12 +539,12 @@ func DecodeOneToChunk(b []byte, chk *chunk.Chunk, colIdx int, ft *types.FieldTyp
}
chk.AppendBytes(colIdx, v)
case decimalFlag:
var d types.Datum
b, d, err = DecodeDecimal(b)
var dec *types.MyDecimal
b, dec, err = DecodeDecimal(b)
if err != nil {
return nil, errors.Trace(err)
}
chk.AppendMyDecimal(colIdx, d.GetMysqlDecimal())
chk.AppendMyDecimal(colIdx, dec)
case durationFlag:
var r int64
b, r, err = DecodeInt(b)

View File

@ -35,10 +35,9 @@ func EncodeDecimal(b []byte, dec *types.MyDecimal, precision, frac int) []byte {
}
// DecodeDecimal decodes bytes to decimal.
func DecodeDecimal(b []byte) ([]byte, types.Datum, error) {
var d types.Datum
func DecodeDecimal(b []byte) ([]byte, *types.MyDecimal, error) {
if len(b) < 3 {
return b, d, errors.New("insufficient bytes to decode value")
return b, nil, errors.New("insufficient bytes to decode value")
}
precision := int(b[0])
frac := int(b[1])
@ -47,10 +46,7 @@ func DecodeDecimal(b []byte) ([]byte, types.Datum, error) {
binSize, err := dec.FromBin(b, precision, frac)
b = b[binSize:]
if err != nil {
return b, d, errors.Trace(err)
return b, nil, errors.Trace(err)
}
d.SetLength(precision)
d.SetFrac(frac)
d.SetMysqlDecimal(dec)
return b, d, nil
return b, dec, nil
}

View File

@ -15,7 +15,6 @@ package codec
import (
. "github.com/pingcap/check"
"github.com/pingcap/tidb/sessionctx/stmtctx"
"github.com/pingcap/tidb/types"
"github.com/pingcap/tidb/util/testleak"
)
@ -51,7 +50,7 @@ func (s *testDecimalSuite) TestDecimalCodec(c *C) {
b := EncodeDecimal([]byte{}, datum.GetMysqlDecimal(), datum.Length(), datum.Frac())
_, d, err := DecodeDecimal(b)
c.Assert(err, IsNil)
c.Assert(v.Compare(d.GetMysqlDecimal()), Equals, 0)
c.Assert(v.Compare(d), Equals, 0)
}
}
@ -72,11 +71,7 @@ func testFrac(c *C, v *types.MyDecimal) {
var d1 types.Datum
d1.SetMysqlDecimal(v)
b := EncodeDecimal([]byte{}, d1.GetMysqlDecimal(), d1.Length(), d1.Frac())
_, d2, err := DecodeDecimal(b)
_, dec, err := DecodeDecimal(b)
c.Assert(err, IsNil)
sc := new(stmtctx.StatementContext)
cmp, err := d1.CompareDatum(sc, &d2)
c.Assert(err, IsNil)
c.Assert(cmp, Equals, 0)
c.Assert(d1.GetMysqlDecimal().String(), Equals, d2.GetMysqlDecimal().String())
c.Assert(dec.String(), Equals, v.String())
}