From: Daniele Varrazzo Date: Sun, 9 May 2021 22:52:16 +0000 (+0200) Subject: Add benchmark test for binary numeric X-Git-Tag: 3.0.dev0~48^2~1 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=18b18284cab3061a3722d8ab19c2bb6ec1f880cf;p=thirdparty%2Fpsycopg.git Add benchmark test for binary numeric Conclusion is that for the moment it is better to leave default Decimal dump to text format. Better performance can be obtained accessing the Python C Decimal structure and perform conversion from there. --- diff --git a/psycopg3/psycopg3/types/__init__.py b/psycopg3/psycopg3/types/__init__.py index 3a14205b0..ab01af914 100644 --- a/psycopg3/psycopg3/types/__init__.py +++ b/psycopg3/psycopg3/types/__init__.py @@ -169,9 +169,8 @@ def register_default_globals(ctx: AdaptContext) -> None: IntBinaryDumper.register(int, ctx) FloatDumper.register(float, ctx) FloatBinaryDumper.register(float, ctx) - # TODO: benchmark to work out if the binary dumper is faster - # (the binary format is usually larger) - # for now leaving the text format as default. + # The binary dumper is currently some 30% slower, so default to text + # (see tests/scripts/testdec.py for a rough benchmark) DecimalBinaryDumper.register("decimal.Decimal", ctx) DecimalDumper.register("decimal.Decimal", ctx) Int2Dumper.register(Int2, ctx) diff --git a/psycopg3_c/psycopg3_c/types/numeric.pyx b/psycopg3_c/psycopg3_c/types/numeric.pyx index c0d8e7224..72e6586ef 100644 --- a/psycopg3_c/psycopg3_c/types/numeric.pyx +++ b/psycopg3_c/psycopg3_c/types/numeric.pyx @@ -554,6 +554,12 @@ cdef class DecimalBinaryDumper(CDumper): cdef Py_ssize_t cdump(self, obj, bytearray rv, Py_ssize_t offset) except -1: + # TODO: this implementation is about 30% slower than the text dump. + # This might be probably optimised by accessing the C structure of + # the Decimal object, if available, which would save the creation of + # several intermediate Python objects (the DecimalTuple, the digits + # tuple, and then accessing them). + cdef object t = obj.as_tuple() cdef int sign = t[0] cdef tuple digits = t[1] diff --git a/tests/scripts/dectest.py b/tests/scripts/dectest.py new file mode 100644 index 000000000..cb143ebd8 --- /dev/null +++ b/tests/scripts/dectest.py @@ -0,0 +1,56 @@ +""" +A quick and rough performance comparison of text vs. binary Decimal adaptation +""" +from random import randrange +from decimal import Decimal +import psycopg3 +from psycopg3 import sql + +ncols = 10 +nrows = 500000 +format = psycopg3.pq.Format.BINARY +test = "copy" + + +def main(): + cnn = psycopg3.connect() + + cnn.execute( + sql.SQL("create table testdec ({})").format( + sql.SQL(", ").join( + [ + sql.SQL("{} numeric(10,2)").format(sql.Identifier(f"t{i}")) + for i in range(ncols) + ] + ) + ) + ) + cur = cnn.cursor() + + if test == "copy": + with cur.copy( + f"copy testdec from stdin (format {format.name})" + ) as copy: + for j in range(nrows): + copy.write_row( + [ + Decimal(randrange(10000000000)) / 100 + for i in range(ncols) + ] + ) + + elif test == "insert": + ph = ["%t", "%b"][format] + cur.executemany( + "insert into testdec values (%s)" % ", ".join([ph] * ncols), + ( + [Decimal(randrange(10000000000)) / 100 for i in range(ncols)] + for j in range(nrows) + ), + ) + else: + raise Exception(f"bad test: {test}") + + +if __name__ == "__main__": + main()