Added int8 binary decoding
Refactored benchmarks
This commit is contained in:
+230
-102
@@ -6,22 +6,24 @@ import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
var testDataLoaded bool
|
||||
var testJoinsDataLoaded bool
|
||||
var narrowTestDataLoaded bool
|
||||
var int4TextVsBinaryTestDataLoaded bool
|
||||
var int8TextVsBinaryTestDataLoaded bool
|
||||
|
||||
func loadTestData() {
|
||||
if testDataLoaded {
|
||||
func mustPrepare(b *testing.B, conn *Connection, name, sql string) {
|
||||
if err := conn.Prepare(name, sql); err != nil {
|
||||
b.Fatalf("Could not prepare %v: %v", name, err)
|
||||
}
|
||||
}
|
||||
|
||||
func createNarrowTestData(b *testing.B, conn *Connection) {
|
||||
if narrowTestDataLoaded {
|
||||
return
|
||||
}
|
||||
|
||||
var err error
|
||||
|
||||
conn := getSharedConnection()
|
||||
|
||||
_, err = conn.Execute(`
|
||||
if _, err := conn.Execute(`
|
||||
drop table if exists narrow;
|
||||
drop table if exists product_component;
|
||||
drop table if exists component;
|
||||
drop table if exists product;
|
||||
|
||||
create table narrow(
|
||||
id serial primary key,
|
||||
@@ -35,6 +37,98 @@ func loadTestData() {
|
||||
select (random()*1000000)::int, (random()*1000000)::int, (random()*1000000)::int, (random()*1000000)::int
|
||||
from generate_series(1, 10000);
|
||||
|
||||
analyze narrow;
|
||||
`); err != nil {
|
||||
panic(fmt.Sprintf("Unable to create narrow test data: %v", err))
|
||||
}
|
||||
|
||||
mustPrepare(b, conn, "getNarrowById", "select * from narrow where id=$1")
|
||||
mustPrepare(b, conn, "getMultipleNarrowById", "select * from narrow where id between $1 and $2")
|
||||
|
||||
narrowTestDataLoaded = true
|
||||
}
|
||||
|
||||
func BenchmarkSelectRowSimpleNarrow(b *testing.B) {
|
||||
conn := getSharedConnection()
|
||||
createNarrowTestData(b, conn)
|
||||
|
||||
// Get random ids outside of timing
|
||||
ids := make([]int32, b.N)
|
||||
for i := 0; i < b.N; i++ {
|
||||
ids[i] = 1 + rand.Int31n(9999)
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
if _, err := conn.SelectRow("select * from narrow where id=$1", ids[i]); err != nil {
|
||||
b.Fatalf("Failure while benchmarking: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkSelectRowPreparedNarrow(b *testing.B) {
|
||||
conn := getSharedConnection()
|
||||
createNarrowTestData(b, conn)
|
||||
|
||||
// Get random ids outside of timing
|
||||
ids := make([]int32, b.N)
|
||||
for i := 0; i < b.N; i++ {
|
||||
ids[i] = 1 + rand.Int31n(9999)
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
if _, err := conn.SelectRow("getNarrowById", ids[i]); err != nil {
|
||||
b.Fatalf("Failure while benchmarking: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkSelectRowsSimpleNarrow(b *testing.B) {
|
||||
conn := getSharedConnection()
|
||||
createNarrowTestData(b, conn)
|
||||
|
||||
// Get random ids outside of timing
|
||||
ids := make([]int32, b.N)
|
||||
for i := 0; i < b.N; i++ {
|
||||
ids[i] = 1 + rand.Int31n(9999)
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
if _, err := conn.SelectRows("select * from narrow where id between $1 and $2", ids[i], ids[i]+10); err != nil {
|
||||
b.Fatalf("Failure while benchmarking: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkSelectRowsPreparedNarrow(b *testing.B) {
|
||||
conn := getSharedConnection()
|
||||
createNarrowTestData(b, conn)
|
||||
|
||||
// Get random ids outside of timing
|
||||
ids := make([]int32, b.N)
|
||||
for i := 0; i < b.N; i++ {
|
||||
ids[i] = 1 + rand.Int31n(9999)
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
if _, err := conn.SelectRows("getMultipleNarrowById", ids[i], ids[i]+10); err != nil {
|
||||
b.Fatalf("Failure while benchmarking: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func createJoinsTestData(b *testing.B, conn *Connection) {
|
||||
if testJoinsDataLoaded {
|
||||
return
|
||||
}
|
||||
|
||||
if _, err := conn.Execute(`
|
||||
drop table if exists product_component;
|
||||
drop table if exists component;
|
||||
drop table if exists product;
|
||||
|
||||
create table component(
|
||||
id serial primary key,
|
||||
@@ -82,22 +176,11 @@ func loadTestData() {
|
||||
create index on product_component(component_id);
|
||||
|
||||
analyze;
|
||||
`)
|
||||
if err != nil {
|
||||
`); err != nil {
|
||||
panic(fmt.Sprintf("Unable to create test data: %v", err))
|
||||
}
|
||||
|
||||
err = conn.Prepare("getNarrowById", "select * from narrow where id=$1")
|
||||
if err != nil {
|
||||
panic("Unable to prepare getNarrowById")
|
||||
}
|
||||
|
||||
err = conn.Prepare("getMultipleNarrowById", "select * from narrow where id between $1 and $2")
|
||||
if err != nil {
|
||||
panic("Unable to prepare getMultipleNarrowById")
|
||||
}
|
||||
|
||||
err = conn.Prepare("joinAggregate", `
|
||||
mustPrepare(b, conn, "joinAggregate", `
|
||||
select product.id, sum(cost*quantity) as total_cost
|
||||
from product
|
||||
join product_component on product.id=product_component.product_id
|
||||
@@ -106,88 +189,13 @@ func loadTestData() {
|
||||
having sum(weight*quantity) > 10
|
||||
order by total_cost desc
|
||||
`)
|
||||
if err != nil {
|
||||
panic("Unable to prepare joinAggregate")
|
||||
}
|
||||
|
||||
testDataLoaded = true
|
||||
}
|
||||
|
||||
func BenchmarkSelectRowSimpleNarrow(b *testing.B) {
|
||||
loadTestData()
|
||||
conn := getSharedConnection()
|
||||
|
||||
// Get random ids outside of timing
|
||||
ids := make([]int32, b.N)
|
||||
for i := 0; i < b.N; i++ {
|
||||
ids[i] = 1 + rand.Int31n(9999)
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
if _, err := conn.SelectRow("select * from narrow where id=$1", ids[i]); err != nil {
|
||||
b.Fatalf("Failure while benchmarking: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkSelectRowPreparedNarrow(b *testing.B) {
|
||||
loadTestData()
|
||||
conn := getSharedConnection()
|
||||
|
||||
// Get random ids outside of timing
|
||||
ids := make([]int32, b.N)
|
||||
for i := 0; i < b.N; i++ {
|
||||
ids[i] = 1 + rand.Int31n(9999)
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
if _, err := conn.SelectRow("getNarrowById", ids[i]); err != nil {
|
||||
b.Fatalf("Failure while benchmarking: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkSelectRowsSimpleNarrow(b *testing.B) {
|
||||
loadTestData()
|
||||
conn := getSharedConnection()
|
||||
|
||||
// Get random ids outside of timing
|
||||
ids := make([]int32, b.N)
|
||||
for i := 0; i < b.N; i++ {
|
||||
ids[i] = 1 + rand.Int31n(9999)
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
if _, err := conn.SelectRows("select * from narrow where id between $1 and $2", ids[i], ids[i]+10); err != nil {
|
||||
b.Fatalf("Failure while benchmarking: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkSelectRowsPreparedNarrow(b *testing.B) {
|
||||
loadTestData()
|
||||
conn := getSharedConnection()
|
||||
|
||||
// Get random ids outside of timing
|
||||
ids := make([]int32, b.N)
|
||||
for i := 0; i < b.N; i++ {
|
||||
ids[i] = 1 + rand.Int31n(9999)
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
if _, err := conn.SelectRows("getMultipleNarrowById", ids[i], ids[i]+10); err != nil {
|
||||
b.Fatalf("Failure while benchmarking: %v", err)
|
||||
}
|
||||
}
|
||||
testJoinsDataLoaded = true
|
||||
}
|
||||
|
||||
func BenchmarkSelectRowsSimpleJoins(b *testing.B) {
|
||||
loadTestData()
|
||||
conn := getSharedConnection()
|
||||
createJoinsTestData(b, conn)
|
||||
|
||||
sql := `
|
||||
select product.id, sum(cost*quantity) as total_cost
|
||||
@@ -208,8 +216,8 @@ func BenchmarkSelectRowsSimpleJoins(b *testing.B) {
|
||||
}
|
||||
|
||||
func BenchmarkSelectRowsPreparedJoins(b *testing.B) {
|
||||
loadTestData()
|
||||
conn := getSharedConnection()
|
||||
createJoinsTestData(b, conn)
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
@@ -218,3 +226,123 @@ func BenchmarkSelectRowsPreparedJoins(b *testing.B) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func createInt4TextVsBinaryTestData(b *testing.B, conn *Connection) {
|
||||
if int4TextVsBinaryTestDataLoaded {
|
||||
return
|
||||
}
|
||||
|
||||
if _, err := conn.Execute(`
|
||||
drop table if exists t;
|
||||
|
||||
create temporary table t(
|
||||
a int4 not null,
|
||||
b int4 not null,
|
||||
c int4 not null,
|
||||
d int4 not null,
|
||||
e int4 not null
|
||||
);
|
||||
|
||||
insert into t(a, b, c, d, e)
|
||||
select
|
||||
(random() * 1000000)::int4, (random() * 1000000)::int4, (random() * 1000000)::int4, (random() * 1000000)::int4, (random() * 1000000)::int4
|
||||
from generate_series(1, 10);
|
||||
`); err != nil {
|
||||
b.Fatalf("Could not set up test data: %v", err)
|
||||
}
|
||||
|
||||
int4TextVsBinaryTestDataLoaded = true
|
||||
}
|
||||
|
||||
func BenchmarkInt4Text(b *testing.B) {
|
||||
conn := getSharedConnection()
|
||||
createInt4TextVsBinaryTestData(b, conn)
|
||||
|
||||
binaryDecoder := valueTranscoders[oid(23)].DecodeBinary
|
||||
valueTranscoders[oid(23)].DecodeBinary = nil
|
||||
defer func() { valueTranscoders[oid(23)].DecodeBinary = binaryDecoder }()
|
||||
|
||||
mustPrepare(b, conn, "selectInt32", "select * from t")
|
||||
defer func() { conn.Deallocate("selectInt32") }()
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
if _, err := conn.SelectRows("selectInt32"); err != nil {
|
||||
b.Fatalf("Failure while benchmarking: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkInt4Binary(b *testing.B) {
|
||||
conn := getSharedConnection()
|
||||
createInt4TextVsBinaryTestData(b, conn)
|
||||
mustPrepare(b, conn, "selectInt32", "select * from t")
|
||||
defer func() { conn.Deallocate("selectInt32") }()
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
if _, err := conn.SelectRows("selectInt32"); err != nil {
|
||||
b.Fatalf("Failure while benchmarking: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func createInt8TextVsBinaryTestData(b *testing.B, conn *Connection) {
|
||||
if int8TextVsBinaryTestDataLoaded {
|
||||
return
|
||||
}
|
||||
|
||||
if _, err := conn.Execute(`
|
||||
drop table if exists t;
|
||||
|
||||
create temporary table t(
|
||||
a int8 not null,
|
||||
b int8 not null,
|
||||
c int8 not null,
|
||||
d int8 not null,
|
||||
e int8 not null
|
||||
);
|
||||
|
||||
insert into t(a, b, c, d, e)
|
||||
select
|
||||
(random() * 1000000)::int8, (random() * 1000000)::int8, (random() * 1000000)::int8, (random() * 1000000)::int8, (random() * 1000000)::int8
|
||||
from generate_series(1, 10);
|
||||
`); err != nil {
|
||||
b.Fatalf("Could not set up test data: %v", err)
|
||||
}
|
||||
|
||||
int8TextVsBinaryTestDataLoaded = true
|
||||
}
|
||||
|
||||
func BenchmarkInt8Text(b *testing.B) {
|
||||
conn := getSharedConnection()
|
||||
createInt8TextVsBinaryTestData(b, conn)
|
||||
|
||||
binaryDecoder := valueTranscoders[oid(20)].DecodeBinary
|
||||
valueTranscoders[oid(20)].DecodeBinary = nil
|
||||
defer func() { valueTranscoders[oid(20)].DecodeBinary = binaryDecoder }()
|
||||
|
||||
mustPrepare(b, conn, "selectInt64", "select * from t")
|
||||
defer func() { conn.Deallocate("selectInt64") }()
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
if _, err := conn.SelectRows("selectInt64"); err != nil {
|
||||
b.Fatalf("Failure while benchmarking: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkInt8Binary(b *testing.B) {
|
||||
conn := getSharedConnection()
|
||||
createInt8TextVsBinaryTestData(b, conn)
|
||||
mustPrepare(b, conn, "selectInt64", "select * from t")
|
||||
defer func() { conn.Deallocate("selectInt64") }()
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
if _, err := conn.SelectRows("selectInt64"); err != nil {
|
||||
b.Fatalf("Failure while benchmarking: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+17
-1
@@ -281,6 +281,12 @@ func (c *Connection) Prepare(name, sql string) (err error) {
|
||||
ps.ParameterOids = c.rxParameterDescription(r)
|
||||
case rowDescription:
|
||||
ps.FieldDescriptions = c.rxRowDescription(r)
|
||||
for i := range ps.FieldDescriptions {
|
||||
oid := ps.FieldDescriptions[i].DataType
|
||||
if valueTranscoders[oid] != nil && valueTranscoders[oid].DecodeBinary != nil {
|
||||
ps.FieldDescriptions[i].FormatCode = 1
|
||||
}
|
||||
}
|
||||
case readyForQuery:
|
||||
c.preparedStatements[name] = &ps
|
||||
return
|
||||
@@ -339,6 +345,7 @@ func (c *Connection) sendPreparedQuery(ps *PreparedStatement, arguments ...inter
|
||||
buf.WriteByte(0)
|
||||
buf.WriteString(ps.Name)
|
||||
buf.WriteByte(0)
|
||||
|
||||
binary.Write(buf, binary.BigEndian, int16(len(ps.ParameterOids)))
|
||||
for _, oid := range ps.ParameterOids {
|
||||
transcoder := valueTranscoders[oid]
|
||||
@@ -356,7 +363,16 @@ func (c *Connection) sendPreparedQuery(ps *PreparedStatement, arguments ...inter
|
||||
}
|
||||
transcoder.EncodeTo(buf, arguments[i])
|
||||
}
|
||||
binary.Write(buf, binary.BigEndian, int16(0))
|
||||
|
||||
binary.Write(buf, binary.BigEndian, int16(len(ps.FieldDescriptions)))
|
||||
for _, fd := range ps.FieldDescriptions {
|
||||
transcoder := valueTranscoders[fd.DataType]
|
||||
if transcoder != nil && transcoder.DecodeBinary != nil {
|
||||
binary.Write(buf, binary.BigEndian, int16(1))
|
||||
} else {
|
||||
binary.Write(buf, binary.BigEndian, int16(0))
|
||||
}
|
||||
}
|
||||
|
||||
err = c.txMsg('B', buf)
|
||||
if err != nil {
|
||||
|
||||
@@ -30,6 +30,12 @@ func (r *MessageReader) ReadInt32() int32 {
|
||||
return n
|
||||
}
|
||||
|
||||
func (r *MessageReader) ReadInt64() int64 {
|
||||
n := int64(binary.BigEndian.Uint64((*r)[:8]))
|
||||
*r = (*r)[8:]
|
||||
return n
|
||||
}
|
||||
|
||||
func (r *MessageReader) ReadOid() oid {
|
||||
n := oid(binary.BigEndian.Uint32((*r)[:4]))
|
||||
*r = (*r)[4:]
|
||||
|
||||
+20
-4
@@ -34,8 +34,9 @@ func init() {
|
||||
|
||||
// int8
|
||||
valueTranscoders[oid(20)] = &valueTranscoder{
|
||||
DecodeText: decodeInt8FromText,
|
||||
EncodeTo: encodeInt8}
|
||||
DecodeText: decodeInt8FromText,
|
||||
DecodeBinary: decodeInt8FromBinary,
|
||||
EncodeTo: encodeInt8}
|
||||
|
||||
// int2
|
||||
valueTranscoders[oid(21)] = &valueTranscoder{
|
||||
@@ -44,8 +45,9 @@ func init() {
|
||||
|
||||
// int4
|
||||
valueTranscoders[oid(23)] = &valueTranscoder{
|
||||
DecodeText: decodeInt4FromText,
|
||||
EncodeTo: encodeInt4}
|
||||
DecodeText: decodeInt4FromText,
|
||||
DecodeBinary: decodeInt4FromBinary,
|
||||
EncodeTo: encodeInt4}
|
||||
|
||||
// text
|
||||
valueTranscoders[oid(25)] = &valueTranscoder{
|
||||
@@ -97,6 +99,13 @@ func decodeInt8FromText(mr *MessageReader, size int32) interface{} {
|
||||
return n
|
||||
}
|
||||
|
||||
func decodeInt8FromBinary(mr *MessageReader, size int32) interface{} {
|
||||
if size != 8 {
|
||||
panic("Received an invalid size for an int8")
|
||||
}
|
||||
return mr.ReadInt64()
|
||||
}
|
||||
|
||||
func encodeInt8(buf *bytes.Buffer, value interface{}) {
|
||||
v := value.(int64)
|
||||
s := strconv.FormatInt(int64(v), 10)
|
||||
@@ -129,6 +138,13 @@ func decodeInt4FromText(mr *MessageReader, size int32) interface{} {
|
||||
return int32(n)
|
||||
}
|
||||
|
||||
func decodeInt4FromBinary(mr *MessageReader, size int32) interface{} {
|
||||
if size != 4 {
|
||||
panic("Received an invalid size for an int4")
|
||||
}
|
||||
return mr.ReadInt32()
|
||||
}
|
||||
|
||||
func encodeInt4(buf *bytes.Buffer, value interface{}) {
|
||||
v := value.(int32)
|
||||
s := strconv.FormatInt(int64(v), 10)
|
||||
|
||||
Reference in New Issue
Block a user