Skip to content

agtype performance optimizations - #2510

Open
AntufeevMaksim wants to merge 5 commits into
apache:masterfrom
AntufeevMaksim:pr/agtype
Open

agtype performance optimizations#2510
AntufeevMaksim wants to merge 5 commits into
apache:masterfrom
AntufeevMaksim:pr/agtype

Conversation

@AntufeevMaksim

@AntufeevMaksim AntufeevMaksim commented Aug 12, 2026

Copy link
Copy Markdown

agtype performance optimizations

replace binary search in find_agtype_value_from_container() with linear for small objects.

Motivation / Problem:

In the current implementation of find_agtype_value_from_container, searching for a key in an agtype object always uses binary search. For each probe during the binary search, we must call get_agtype_offset(). This function walks backwards through the container's entry array to find the nearest preceding element with a stored absolute offset (AGTE_HAS_OFF), summing lengths along the way.

Solution

Linear search is now used for objects with pair counts <= AGTYPE_OBJECT_LINEAR_SEARCH_THRESHOLD (default: 8).
During linear search, key offsets are calculated incrementally by adding the size of previous elements via AGTE_ADVANCE_OFFSET, completely eliminating backward walks and repeated get_agtype_offset() calls.

Result: TPS increase of up to 5%

before                                                                        after
=====================================                             |           =====================================
AddForumMemberMutation                                            |           AddForumMemberMutation
=====================================                             |           =====================================
- 109008 iterations                                               | [ +2.16%]- 111368 iterations
- 3710 tps (overall)                                              | [ +3.15%]- 3827 tps (overall)
- 3882 tps (last 5 sec)                                           | [ +2.45%]- 3977 tps (last 5 sec)
- 3217420 ns average latency                                      | [ +3.07%]- 3118775 ns average latency
peak mem: 329.1064453125kb                                        | [ -0.15%]peak mem: 329.615234375kb
avg mem: 297.72008850524475kb                                     | [ +1.26%]avg mem: 293.9697133657095kb
=====================================                             |           =====================================
CreateKnowsMutation                                               |           CreateKnowsMutation
=====================================                             |           =====================================
- 72530 iterations                                                | [ +1.70%]- 73766 iterations
- 2440 tps (overall)                                              | [ +3.77%]- 2532 tps (overall)
- 2540 tps (last 5 sec)                                           | [ +3.58%]- 2631 tps (last 5 sec)
- 4893768 ns average latency                                      | [ +3.74%]- 4710979 ns average latency
peak mem: 324.822265625kb                                         | [ -0.17%]peak mem: 325.361328125kb
avg mem: 292.7277922453704kb                                      | [ -0.02%]avg mem: 292.7764400652985kb
=====================================                             |           =====================================
MessageContentQuery                                               |           MessageContentQuery
=====================================                             |           =====================================
- 18970 iterations                                                | [ +2.55%]- 19454 iterations
- 633 tps (overall)                                               | [ +4.74%]- 663 tps (overall)
- 650 tps (last 5 sec)                                            | [ +4.46%]- 679 tps (last 5 sec)
- 18899376 ns average latency                                     | [ +4.53%]- 18043070 ns average latency
peak mem: 268.1611328125kb                                        | [ -0.10%]peak mem: 268.4248046875kb
avg mem: 238.71351412259617kb                                     | [ +0.25%]avg mem: 238.1108856201172kb

blue - before
orange - after

image-35

CreateKnowsMutation [before]
image-39

CreateKnowsMutation [after]
image-40

Optimize agtype_access_operator by avoiding variadic array construction

Motivation / Problem:

extract_variadic_args() took around 50% of agtype_access_operator execution time.
ExecEvalArrayExpr(), which is used to construct the variadic array, also accounted
for a significant part of transaction execution time.

Solution

To avoid these overheads, we replace the original

agtype_access_operator(VARIADIC agtype[])

with

agtype_access_operator(VARIADIC "any")

This allows the function to be called in a non-variadic way. In
particular, Cypher property and map access expressions now pass their
arguments directly instead of constructing an agtype array.

Note

There is an important difference between VARIADIC agtype[] and
VARIADIC "any". With VARIADIC agtype[], PostgreSQL automatically packs
arguments passed using the regular function-call syntax into an
agtype[] array. With VARIADIC "any", this automatic conversion to an
agtype array is no longer available for the non-variadic call path.
Therefore, agtype_access_operator now performs the required type
conversion itself for non-agtype arguments.

The original behavior is preserved: arguments are still converted to
agtype before being processed, and the variadic path remains available
for calls where the number of arguments is not known in advance.

Regression tests were also updated because the function signature and
the generated expression trees have changed. Expected EXPLAIN output
now contains non-variadic agtype_access_operator calls instead of
VARIADIC ARRAY expressions.

Result: TPS increase of up to 30%

latency reduction of up to 23%

before                                                                        after
=====================================                             |           =====================================
CreateCommentMutationWhere                                        |           CreateCommentMutationWhere
=====================================                             |           =====================================
- 5535 iterations                                                 | [+33.53%]- 7391 iterations
- 188 tps (overall)                                               | [+30.85%]- 246 tps (overall)
- 177 tps (last 5 sec)                                            | [+30.51%]- 231 tps (last 5 sec)
- 63703815 ns average latency                                     | [+23.76%]- 48568704 ns average latency
peak mem: 712.134765625kb                                         | [ -3.45%]peak mem: 736.71484375kb
avg mem: 471.55885074013156kb                                     | [ -8.95%]avg mem: 513.7577865735619kb
                                                             |           
=====================================                             |           =====================================
CreateForumWithTagsMutationWhere                                  |           CreateForumWithTagsMutationWhere
=====================================                             |           =====================================
- 29875 iterations                                                | [+32.09%]- 39462 iterations
- 1026 tps (overall)                                              | [+29.82%]- 1332 tps (overall)
- 1069 tps (last 5 sec)                                           | [+30.40%]- 1394 tps (last 5 sec)
- 11623780 ns average latency                                     | [+22.84%]- 8969228 ns average latency
peak mem: 536.537109375kb                                         | [ -1.27%]peak mem: 543.3642578125kb
avg mem: 440.198734642094kb                                       | [ -3.06%]avg mem: 453.679234375kb

blue - before
orange - after

image-9 image-10

CreateForumWithTagsMutationWhere [before]
image-45

CreateForumWithTagsMutationWhere [after]
image-46

Replace per-iterator heap allocation with an inline iterator stack backed by dynamically allocated chunks.

Motivation / Problem:

agtype_iterator objects were previously allocated individually with palloc() during traversal.

Solution

The first AGI_INLINE_ITERS (default 8) iterators are stored directly in agtype_traversal using stack memory

When the traversal depth exceeds the inline capacity, additional iterators are stored in dynamically allocated chunks.

The heap-based part of the stack is organized as a linked list of chunks with exponentially increasing capacity. Once a chunk is allocated, it is kept for the lifetime of the traversal and reused when the traversal reaches the same depth again. This avoids repeated palloc()/pfree() calls when moving between nested containers.

Result: TPS increase of up to 18%

latency reduction of up to 15%

before                                                                        after
=====================================                             |           =====================================
LikeCommentMutation                                               |           LikeCommentMutation
=====================================                             |           =====================================
- 32420 iterations                                                | [+15.90%]- 37575 iterations
- 1097 tps (overall)                                              | [+14.86%]- 1260 tps (overall)
- 1131 tps (last 5 sec)                                           | [+15.38%]- 1305 tps (last 5 sec)
- 10898230 ns average latency                                     | [+12.89%]- 9492943 ns average latency
peak mem: 316.8525390625kb                                        | [ -0.12%]peak mem: 317.244140625kb
avg mem: 279.11435041756465kb                                     | [ -0.31%]avg mem: 279.98338188559325kb
=====================================                             |           =====================================
LikePostMutation                                                  |           LikePostMutation
=====================================                             |           =====================================
- 29517 iterations                                                | [+16.89%]- 34502 iterations
- 1003 tps (overall)                                              | [+15.85%]- 1162 tps (overall)
- 1034 tps (last 5 sec)                                           | [+16.83%]- 1208 tps (last 5 sec)
- 11917714 ns average latency                                     | [+13.64%]- 10292022 ns average latency
peak mem: 319.1064453125kb                                        | [ -0.30%]peak mem: 320.0498046875kb
avg mem: 279.390185546875kb                                       | [ -1.27%]avg mem: 282.9513555021368kb
=====================================                             |           =====================================
MessageAuthorQuery                                                |           MessageAuthorQuery
=====================================                             |           =====================================
- 16858 iterations                                                | [+17.18%]- 19754 iterations
- 577 tps (overall)                                               | [+15.42%]- 666 tps (overall)
- 595 tps (last 5 sec)                                            | [+15.97%]- 690 tps (last 5 sec)
- 20693969 ns average latency                                     | [+13.24%]- 17955045 ns average latency
peak mem: 336.0947265625kb                                        | [ -0.03%]peak mem: 336.2099609375kb
avg mem: 291.8486328125kb                                         | [ -0.79%]avg mem: 294.1560284269958kb
=====================================                             |           =====================================
MessageContentQuery                                               |           MessageContentQuery
=====================================                             |           =====================================
- 18346 iterations                                                | [+21.01%]- 22201 iterations
- 632 tps (overall)                                               | [+18.51%]- 749 tps (overall)
- 645 tps (last 5 sec)                                            | [+19.53%]- 771 tps (last 5 sec)
- 18925681 ns average latency                                     | [+15.67%]- 15960851 ns average latency
peak mem: 268.3916015625kb                                        | [ -0.00%]peak mem: 268.400390625kb
avg mem: 236.346282710874kb                                       | [ -0.65%]avg mem: 237.88215095766128kb

blue - before
orange - after

image-16 image-18

MessageAutorQuery [before]
image-12

MessageAutorQuery [after]
image-13

agtype_build_map()

Motivation / Problem:

agtype_categorize_type() accounted for around 31% of agtype_build_map() execution time. Type categorization is based on the argument type OID, which is obtained from the function expression stored in FmgrInfo. The expression tree associated with a particular FmgrInfo does not change between its executions, so the resulting type metadata can be safely cached for subsequent calls using the same FmgrInfo.

extract_variadic_agrs() accounted for around 13% of agtype_build_map() execution time.

pfree_agtype_value() accounted for around 4% of agtype_build_map() execution time.

Solution

Add a per-function type cache backed by a hash table. The cache stores the category and output function for each encountered type OID, avoiding repeated calls to agtype_categorize_type() for the same types.

The change also adds a fast path for non-variadic calls. Previously, extract_variadic_args() was used for both ordinary and VARIADIC calls. For a non-variadic call, the arguments are already available in FunctionCallInfo, so allocating and populating separate args, nulls, and types arrays is unnecessary.

Add a temporary memory context which give us a possibility to remove pfree_agtype_value() calls.

Result: TPS increase of up to 35%

latency reduction of up to 25%

before                                                                        after
=====================================                             |           =====================================
CreateCommentMutation                                             |           CreateCommentMutation
=====================================                             |           =====================================
- 10412 iterations                                                | [+12.13%]- 11675 iterations
- 352 tps (overall)                                               | [+12.50%]- 396 tps (overall)
- 357 tps (last 5 sec)                                            | [+14.29%]- 408 tps (last 5 sec)
- 33981716 ns average latency                                     | [+11.15%]- 30191071 ns average latency
peak mem: 546.3203125kb                                           | [ -0.22%]peak mem: 547.5244140625kb
avg mem: 433.9193993283991kb                                      | [ -0.66%]avg mem: 436.77863451086955kb
=====================================                             |           ====================================
=====================================                             |           =====================================
CreateForumWithTagsMutation                                       |           CreateForumWithTagsMutation
=====================================                             |           =====================================
- 10112 iterations                                                | [+38.29%]- 13984 iterations
- 345 tps (overall)                                               | [+35.07%]- 466 tps (overall)
- 354 tps (last 5 sec)                                            | [+35.31%]- 479 tps (last 5 sec)
- 34593060 ns average latency                                     | [+25.92%]- 25626475 ns average latency
peak mem: 510.61328125kb                                          | [ -1.80%]peak mem: 519.79296875kb
avg mem: 370.85441147985534kb                                     | [ -6.38%]avg mem: 394.5214111328125kb

blue - before
orange - after

image-27

CreateForumWithTagsMutation [before]
image-22

CreateForumWithTagsMutation [after]
image-23

Replace get_ith_agtype_value_from_container with get_ith_agtype_value_from_container_no_copy

Motivation / Problem:

get_ith_agtype_value_from_container performs a copy of strings, numerics, vertices, edges, and paths. However, in some functions like agtype_access_operator and agtype_add, we don't change the agtype_value received from get_ith_agtype_value_from_container, which results in unnecessary copy overhead.

Solution

Create a get_ith_agtype_value_from_container_no_copy function that uses fill_agtype_value_no_copy, and replace calls to get_ith_agtype_value_from_container with get_ith_agtype_value_from_container_no_copy where possible.

Result: TPS increase of up to 4%

latency reduction of up to 4%

before                                                                        after
=====================================                             |           =====================================
CreateCommentMutationWhere                                        |           CreateCommentMutationWhere
=====================================                             |           =====================================
- 5482 iterations                                                 | [ +6.73%]- 5851 iterations
- 188 tps (overall)                                               | [ +3.72%]- 195 tps (overall)
- 176 tps (last 5 sec)                                            | [ +2.84%]- 181 tps (last 5 sec)
- 63695049 ns average latency                                     | [ +3.71%]- 61331612 ns average latency
peak mem: 707.1669921875kb                                        | [ -0.93%]peak mem: 713.7177734375kb
avg mem: 472.549072265625kb                                       | [ -1.08%]avg mem: 477.6684689405488kb
  
=====================================                             |           =====================================
CreateForumWithTagsMutationWhere                                  |           CreateForumWithTagsMutationWhere
=====================================                             |           =====================================
- 29875 iterations                                                | [ +3.62%]- 30957 iterations
- 1026 tps (overall)                                              | [ +3.61%]- 1063 tps (overall)
- 1069 tps (last 5 sec)                                           | [ +2.62%]- 1097 tps (last 5 sec)
- 11623780 ns average latency                                     | [ +3.38%]- 11231310 ns average latency
peak mem: 536.537109375kb                                         | [ -0.13%]peak mem: 537.2314453125kb
avg mem: 440.198734642094kb                                       | [ -1.46%]avg mem: 446.61580332880436kb

blue - before
orange - after

image-32

CreateForumWithTagsMutationWhere [before]
image-28

CreateForumWithTagsMutationWhere [after]
image-29

final version

(Build including all changes)

Result: TPS increase of up to 51%

latency reduction of up to 34%

before                                                                        after
=====================================                             |           =====================================
AddForumMemberMutation                                            |           AddForumMemberMutation
=====================================                             |           =====================================
- 109715 iterations                                               | [+13.34%]- 124354 iterations
- 3686 tps (overall)                                              | [+12.81%]- 4158 tps (overall)
- 3827 tps (last 5 sec)                                           | [+13.04%]- 4326 tps (last 5 sec)
- 3237355 ns average latency                                      | [+11.32%]- 2870948 ns average latency
peak mem: 329.1845703125kb                                        | [ -0.80%]peak mem: 331.8056640625kb
avg mem: 297.2863680428832kb                                      | [ -0.75%]avg mem: 299.5164264547414kb
=====================================                             |           =====================================
CreateCommentMutation                                             |           CreateCommentMutation
=====================================                             |           =====================================
- 10412 iterations                                                | [+31.44%]- 13686 iterations
- 352 tps (overall)                                               | [+30.11%]- 458 tps (overall)
- 357 tps (last 5 sec)                                            | [+33.05%]- 475 tps (last 5 sec)
- 33981716 ns average latency                                     | [+23.15%]- 26114813 ns average latency
peak mem: 546.3203125kb                                           | [ -0.45%]peak mem: 548.751953125kb
avg mem: 433.9193993283991kb                                      | [ -3.46%]avg mem: 448.95097990117523kb
=====================================                             |           =====================================
CreateCommentMutationWhere                                        |           CreateCommentMutationWhere
=====================================                             |           =====================================
- 5535 iterations                                                 | [+51.20%]- 8369 iterations
- 188 tps (overall)                                               | [+48.94%]- 280 tps (overall)
- 177 tps (last 5 sec)                                            | [+45.76%]- 258 tps (last 5 sec)
- 63703815 ns average latency                                     | [+33.05%]- 42651839 ns average latency
peak mem: 712.134765625kb                                         | [ -3.47%]peak mem: 736.810546875kb
avg mem: 471.55885074013156kb                                     | [-14.13%]avg mem: 538.2127766927083kb
=====================================                             |           =====================================
CreateForumWithTagsMutation                                       |           CreateForumWithTagsMutation
=====================================                             |           =====================================
- 10112 iterations                                                | [+54.07%]- 15580 iterations
- 345 tps (overall)                                               | [+51.88%]- 524 tps (overall)
- 354 tps (last 5 sec)                                            | [+48.59%]- 526 tps (last 5 sec)
- 34593060 ns average latency                                     | [+34.05%]- 22815573 ns average latency
peak mem: 510.61328125kb                                          | [ -2.30%]peak mem: 522.3349609375kb
avg mem: 370.85441147985534kb                                     | [ -8.64%]avg mem: 402.9014227642276kb
=====================================                             |           =====================================
CreateForumWithTagsMutationWhere                                  |           CreateForumWithTagsMutationWhere
=====================================                             |           =====================================
- 29875 iterations                                                | [+46.43%]- 43745 iterations
- 1026 tps (overall)                                              | [+43.57%]- 1473 tps (overall)
- 1069 tps (last 5 sec)                                           | [+45.74%]- 1558 tps (last 5 sec)
- 11623780 ns average latency                                     | [+30.27%]- 8105084 ns average latency
peak mem: 536.537109375kb                                         | [ -1.94%]peak mem: 546.9580078125kb
avg mem: 440.198734642094kb                                       | [ -5.36%]avg mem: 463.792724609375kb
=====================================                             |           =====================================
CreateKnowsMutation                                               |           CreateKnowsMutation
=====================================                             |           =====================================
- 72147 iterations                                                | [+16.35%]- 83944 iterations
- 2418 tps (overall)                                              | [+17.33%]- 2837 tps (overall)
- 2500 tps (last 5 sec)                                           | [+18.08%]- 2952 tps (last 5 sec)
- 4942230 ns average latency                                      | [+14.83%]- 4209111 ns average latency
peak mem: 324.9716796875kb                                        | [ -0.59%]peak mem: 326.89453125kb
avg mem: 292.2816344734252kb                                      | [ -0.73%]avg mem: 294.40927442863807kb
=====================================                             |           =====================================
CreatePersonMutation                                              |           CreatePersonMutation
=====================================                             |           =====================================
- 14619 iterations                                                | [+40.99%]- 20611 iterations
- 491 tps (overall)                                               | [+41.75%]- 696 tps (overall)
- 509 tps (last 5 sec)                                            | [+42.83%]- 727 tps (last 5 sec)
- 24329735 ns average latency                                     | [+29.46%]- 17162878 ns average latency
peak mem: 934.9287109375kb                                        | [ -1.19%]peak mem: 946.0869140625kb
avg mem: 720.4496942934783kb                                      | [ -4.02%]avg mem: 749.4276297433036kb
=====================================                             |           =====================================
LikeCommentMutation                                               |           LikeCommentMutation
=====================================                             |           =====================================
- 32420 iterations                                                | [+20.40%]- 39034 iterations
- 1097 tps (overall)                                              | [+20.51%]- 1322 tps (overall)
- 1131 tps (last 5 sec)                                           | [+21.49%]- 1374 tps (last 5 sec)
- 10898230 ns average latency                                     | [+17.03%]- 9042019 ns average latency
peak mem: 316.8525390625kb                                        | [ -0.19%]peak mem: 317.44140625kb
avg mem: 279.11435041756465kb                                     | [ -0.85%]avg mem: 281.4940995929622kb
=====================================                             |           =====================================
LikePostMutation                                                  |           LikePostMutation
=====================================                             |           =====================================
- 29517 iterations                                                | [+20.44%]- 35551 iterations
- 1003 tps (overall)                                              | [+20.04%]- 1204 tps (overall)
- 1034 tps (last 5 sec)                                           | [+20.02%]- 1241 tps (last 5 sec)
- 11917714 ns average latency                                     | [+16.71%]- 9926633 ns average latency
peak mem: 319.1064453125kb                                        | [ -0.38%]peak mem: 320.3095703125kb
avg mem: 279.390185546875kb                                       | [ -0.62%]avg mem: 281.1136767174587kb
=====================================                             |           =====================================
MessageAuthorQuery                                                |           MessageAuthorQuery
=====================================                             |           =====================================
- 16858 iterations                                                | [+20.68%]- 20344 iterations
- 577 tps (overall)                                               | [+19.93%]- 692 tps (overall)
- 595 tps (last 5 sec)                                            | [+20.17%]- 715 tps (last 5 sec)
- 20693969 ns average latency                                     | [+16.51%]- 17276481 ns average latency
peak mem: 336.0947265625kb                                        | [ -0.04%]peak mem: 336.2177734375kb
avg mem: 291.8486328125kb                                         | [ -0.74%]avg mem: 294.0003041752049kb
=====================================                             |           =====================================
MessageContentQuery                                               |           MessageContentQuery
=====================================                             |           =====================================
- 18346 iterations                                                | [+25.64%]- 23050 iterations
- 632 tps (overall)                                               | [+24.37%]- 786 tps (overall)
- 645 tps (last 5 sec)                                            | [+25.43%]- 809 tps (last 5 sec)
- 18925681 ns average latency                                     | [+19.63%]- 15211222 ns average latency
peak mem: 268.3916015625kb                                        | [ +0.07%]peak mem: 268.1904296875kb
avg mem: 236.346282710874kb                                       | [ -1.40%]avg mem: 239.66357421875kb
=====================================                             |           =====================================
MessageForumAndModeratorsQuery                                    |           MessageForumAndModeratorsQuery
=====================================                             |           =====================================
- 9293 iterations                                                 | [ +9.76%]- 10200 iterations
- 311 tps (overall)                                               | [+11.90%]- 348 tps (overall)
- 327 tps (last 5 sec)                                            | [+10.09%]- 360 tps (last 5 sec)
- 38378279 ns average latency                                     | [+10.57%]- 34322041 ns average latency
peak mem: 887.2958984375kb                                        | [ -0.52%]peak mem: 891.9150390625kb
avg mem: 716.639769345238kb                                       | [ -1.11%]avg mem: 724.6248726222826kb
=====================================                             |           =====================================
MessageRepliesQuery                                               |           MessageRepliesQuery
=====================================                             |           =====================================
- 11727 iterations                                                | [+11.72%]- 13101 iterations
- 396 tps (overall)                                               | [+13.38%]- 449 tps (overall)
- 411 tps (last 5 sec)                                            | [+12.90%]- 464 tps (last 5 sec)
- 30210561 ns average latency                                     | [+11.91%]- 26611426 ns average latency
peak mem: 937.3115234375kb                                        | [ +0.11%]peak mem: 936.2578125kb
avg mem: 727.313513764881kb                                       | [ -2.42%]avg mem: 744.9095248518319kb
=====================================                             |           =====================================
PersonFriendsQuery                                                |           PersonFriendsQuery
=====================================                             |           =====================================
- 2944 iterations                                                 | [ -0.14%]- 2940 iterations
- 100 tps (overall)                                               | [ +1.00%]- 101 tps (overall)
- 101 tps (last 5 sec)                                            | [ +0.99%]- 102 tps (last 5 sec)
- 119429174 ns average latency                                    | [ +1.10%]- 118121288 ns average latency
peak mem: 300.0068359375kb                                        | [ +0.75%]peak mem: 297.7509765625kb
avg mem: 194.2514122596154kb                                      | [ +0.40%]avg mem: 193.47971980733084kb
=====================================                             |           =====================================
PersonProfileQuery                                                |           PersonProfileQuery
=====================================                             |           =====================================
- 11971 iterations                                                | [ +3.84%]- 12431 iterations
- 411 tps (overall)                                               | [ +0.73%]- 414 tps (overall)
- 421 tps (last 5 sec)                                            | [ +0.48%]- 423 tps (last 5 sec)
- 29095769 ns average latency                                     | [ +0.75%]- 28878475 ns average latency
peak mem: 329.53125kb                                             | [+14.85%]peak mem: 280.6044921875kb
avg mem: 274.36148834228516kb                                     | [+12.10%]avg mem: 241.16934041030535kb
=====================================                             |           =====================================
PersonRecentMessagesQuery                                         |           PersonRecentMessagesQuery
=====================================                             |           =====================================
- 40901 iterations                                                | [ +6.54%]- 43574 iterations
- 1365 tps (overall)                                              | [ +6.81%]- 1458 tps (overall)
- 1425 tps (last 5 sec)                                           | [ +6.32%]- 1515 tps (last 5 sec)
- 8762729 ns average latency                                      | [ +6.46%]- 8196441 ns average latency
peak mem: 1181.474609375kb                                        | [ -0.86%]peak mem: 1191.6875kb
avg mem: 930.1805913397607kb                                      | [ -0.64%]avg mem: 936.1678515625kb

blue - before
orange - after

AddForumMemberMutation CreateCommentMutation CreateCommentMutationWhere CreateForumWithTagsMutation CreateForumWithTagsMutationWhere CreateKnowsMutation CreatePersonMutation LikeCommentMutation LikePostMutation MessageAuthorQuery MessageContentQuery MessageForumAndModeratorsQuery MessageRepliesQuery PersonFriendsQuery PersonProfileQuery PersonRecentMessagesQuery

Benchmarking

Benchmarks were conducted on a laptop with 4 performance and 4 power efficient cores. 16 CB RAM.

How to run tests:

  1. Graph creation and population:
    The sf parameter here defines the scale factor of the generated graph.
    psql -d your_database -f generate_graph.sql -v sf=1

  2. Creating wrapper functions for the workload:
    This script sets up the environment and creates functions with the correct parameter mapping for Apache AGE.
    psql -d your_database -f setup_AddForumMemberMutation.sql

  3. Running the load test:
    Running 16 clients for 30 seconds.
    pgbench -d your_database -f workload_AddForumMemberMutation.sql -D sf=1 -c 16 -j 12 -T 30 -n

Test scenarious:
generate_graph.sql
setup_AddForumMemberMutation.sql
setup_CreateCommentMutation.sql
setup_CreateCommentMutationWhere.sql
setup_CreateForumWithTagsMutation.sql
setup_CreateForumWithTagsMutationWhere.sql
setup_CreateKnowsMutation.sql
setup_CreatePersonMutation.sql
setup_LikeCommentMutation.sql
setup_LikePostMutation.sql
setup_MessageAuthorQuery.sql
setup_MessageContentQuery.sql
setup_MessageForumAndModeratorsQuery.sql
setup_MessageRepliesQuery.sql
setup_PersonFriendsQuery.sql
setup_PersonProfileQuery.sql
setup_PersonRecentMessagesQuery.sql
workload_AddForumMemberMutation.sql
workload_CreateCommentMutation.sql
workload_CreateCommentMutationWhere.sql
workload_CreateForumWithTagsMutation.sql
workload_CreateForumWithTagsMutationWhere.sql
workload_CreateKnowsMutation.sql
workload_CreatePersonMutation.sql
workload_LikeCommentMutation.sql
workload_LikePostMutation.sql
workload_MessageAuthorQuery.sql
workload_MessageContentQuery.sql
workload_MessageForumAndModeratorsQuery.sql
workload_MessageRepliesQuery.sql
workload_PersonFriendsQuery.sql
workload_PersonProfileQuery.sql
workload_PersonRecentMessagesQuery.sql

Special thanks to @sandy-bes for pointing out the agtype performance issues, suggesting the initial direction for the optimization, and providing a thorough code review. Your feedback was very helpful in shaping this work.

find_agtype_value_from_container() previously used binary search for
objects of any size. For small objects this was inefficient due to
repeated get_agtype_offset() calls on each random-access probe and
poor cache locality.

Introduce a hybrid search strategy:
- Use sequential linear scan with running key offset tracking via
  AGTE_ADVANCE_OFFSET when pair count <= AGTYPE_OBJECT_LINEAR_SEARCH_THRESHOLD.
  This eliminates backward walks through the children array during
  key comparisons.
- Leverage sorted key order for early termination when the current
  key exceeds the search target.
- Retain binary search for larger objects where O(log N) dominates.

The threshold is set to 8 pairs.

Key length is now derived from the difference between consecutive
offsets instead of calling get_agtype_length(), which is safe for the
current storage format and further reduces CPU overhead.
- Add a non-variadic fast path for agtype_access_operator with direct
  argument passing, avoiding variadic array construction and extraction.
- Update Cypher expression transformation to build non-variadic
  agtype_access_operator calls for map and property access.
- Update regression tests and expected query plans for the new
  non-variadic function calls.
…cked by dynamically allocated chunks. Small traversals now complete without any heap allocations, while deeper traversals transparently fall back to chunk allocation.
…_from_container_no_copy in execute_map_access_operator and agtype arithmetic operations functions.
Add a per-function type cache backed by a hash table to avoid repeated
type categorization for previously seen OIDs.

Add a fast path for non-variadic calls that processes arguments
directly from FunctionCallInfo, avoiding extract_variadic_args() and
its temporary allocations in the common case.

Add a temporary MemoryContext in agtype_build_map() for agtype_value
allocations.
@AntufeevMaksim
AntufeevMaksim marked this pull request as ready for review August 12, 2026 15:13
@AntufeevMaksim AntufeevMaksim changed the title Pr/agtype agtype performance optimizations Aug 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant