From 31e4eba94cf7ac1e6f869d6eafa8c90078da602a Mon Sep 17 00:00:00 2001 From: Diego Fronza Date: Thu, 1 Aug 2024 15:53:05 -0300 Subject: [PATCH] Optmize query denormalization Instead of copying original query text byte by byte, copy data between query placeholders in chunks, example: `INSERT INTO foo(a, b, c) VALUES('test', 100, 'test again)'` Would result in normalized query: `INSERT INTO foo(a, b, c) VALUES($1, $2, $3)` The original patch would copy the parts between placeholders byte by byte, e.g. `INSERT INTO foo(a, b, c) VALUES(`, instead we can copy this whole block at once, 1 function call and maybe 1 buffer re-allocation per call. Also make use of `appendBinaryStringInfo` to avoid calculating string length as we have this info already. --- pg_stat_monitor.c | 55 +++++++++++++++++++++++++++++++---------------- 1 file changed, 37 insertions(+), 18 deletions(-) diff --git a/pg_stat_monitor.c b/pg_stat_monitor.c index 0bb6a494..0f79908c 100644 --- a/pg_stat_monitor.c +++ b/pg_stat_monitor.c @@ -20,6 +20,7 @@ #include "nodes/pg_list.h" #include "utils/guc.h" #include +#include #include "pgstat.h" #include "commands/dbcommands.h" #include "commands/explain.h" @@ -4063,40 +4064,58 @@ get_denormalized_query(const ParamListInfo paramlist, const char *query_text) int i; char **param_text; const char *cursor_ori; + const char *cursor_curr; StringInfoData result_buf; + ptrdiff_t len; param_text = get_params_text_list(paramlist); param_num = paramlist->numParams; current_param = 0; cursor_ori = query_text; + cursor_curr = cursor_ori; initStringInfo(&result_buf); - while(*cursor_ori != '\0') + do { - if(*cursor_ori != '$') + // advance cursor until detecting a placeholder '$' start. + while (*cursor_ori && *cursor_ori != '$') + ++cursor_ori; + + // calculate length of query text before placeholder. + len = cursor_ori - cursor_curr; + + // check if end of string is reached + if (!*cursor_ori) { - /* copy the origin query string to result*/ - appendStringInfoChar(&result_buf,*cursor_ori); - cursor_ori++; + // there may have remaining query data to append + if (len > 0) + appendBinaryStringInfo(&result_buf, cursor_curr, len); + + break; } - else - { - /* skip the placeholder */ + + // append query text before the '$' sign found. + if (len > 0) + appendBinaryStringInfo(&result_buf, cursor_curr, len); + + // skip '$' + ++cursor_ori; + + /* skip the placeholder */ + while(*cursor_ori && *cursor_ori >= '0' && *cursor_ori <= '9') cursor_ori++; - while(*cursor_ori >= '0' && *cursor_ori <= '9') - { - cursor_ori++; - } - /* replace the placeholder with actual value */ - appendStringInfo(&result_buf,"%s",param_text[current_param++]); - } - } + + // advance current cursor + cursor_curr = cursor_ori; + + /* replace the placeholder with actual value */ + appendStringInfoString(&result_buf, param_text[current_param++]); + } while (*cursor_ori != '\0'); /* free the query text array*/ for(i = 0; i < param_num; i++) - { pfree(param_text[i]); - } + pfree(param_text); return result_buf;