]> git.ipfire.org Git - thirdparty/psycopg.git/commitdiff
Add benchmark test for binary numeric
authorDaniele Varrazzo <daniele.varrazzo@gmail.com>
Sun, 9 May 2021 22:52:16 +0000 (00:52 +0200)
committerDaniele Varrazzo <daniele.varrazzo@gmail.com>
Sun, 9 May 2021 23:04:10 +0000 (01:04 +0200)
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.

psycopg3/psycopg3/types/__init__.py
psycopg3_c/psycopg3_c/types/numeric.pyx
tests/scripts/dectest.py [new file with mode: 0644]

index 3a14205b0da2f3fffe2a3839f7c6ee9f8f85eae4..ab01af9146cc1921d085e1cc1d63ca18a30d9db9 100644 (file)
@@ -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)
index c0d8e7224ed4355b1db3ac8f28f4a084b0afdc53..72e6586efc7381d7a3a19fb075f238b3100fb8a2 100644 (file)
@@ -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 (file)
index 0000000..cb143eb
--- /dev/null
@@ -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()