On Mon, 2007-11-26 at 09:55 -0500, Tom Lane wrote: > Simon Riggs <[EMAIL PROTECTED]> writes: > > But I think there must be an action that we can take for 8.3 and that > > much runtime should not be given away easily. ISTM that we can win back > > the losses Guillaume has identified, plus gain a little more even. > > Perhaps some sanity could be restored to this discussion by pointing out > that the 2007-01-01 code *also* clocks in at 37% spent in > oper_select_candidate. IOW it's been like this for a very long time.
[I'm replying to the wrong message, I know.] Here's where I am: Basic test was to replace call to oper_select_candidate with a single item that was fed by a hardcoded value for varchar equality operator. This is the oper_cache.v1.patch enclosed; the 5 line patch. Test results were - w/o patch ~10,500 tps with pgbench_varchar.sql - with patch ~15,500 tps with pgbench_varchar.sql (**big gain**) - w/o patch ~16,250 tps with pgbench_integer.sql - with patch ~16,250 tps with pgbench_integer.sql Tables are standard pgbench, varchar test table created using: create table av as select aid::varchar, bid, abalance, filler from accounts; create unique index av_pkey on av (aid); The impact of calling oper_select_candidate() is big enough that it will affect any query that is read only and has 1 or 2 predicates when at least one of them is a VARCHAR_col = const query. What I'm actually proposing is a patch implementing a oper_select_hook function pointer, which allows the user to do anything they want. I'm just re-writing that as a plugin now, but the backend patch is included here for discussion. oper_select_hook.v1.patch -- Simon Riggs 2ndQuadrant http://www.2ndQuadrant.com
Index: src/backend/parser/parse_oper.c =================================================================== RCS file: /home/sriggs/pg/REPOSITORY/pgsql/src/backend/parser/parse_oper.c,v retrieving revision 1.98 diff -c -r1.98 parse_oper.c *** src/backend/parser/parse_oper.c 22 Nov 2007 19:40:25 -0000 1.98 --- src/backend/parser/parse_oper.c 26 Nov 2007 16:28:42 -0000 *************** *** 28,33 **** --- 28,34 ---- #include "utils/syscache.h" #include "utils/typcache.h" + static Oid operOidCache = InvalidOid; static Oid binary_oper_exact(List *opname, Oid arg1, Oid arg2); static FuncDetailCode oper_select_candidate(int nargs, *************** *** 516,534 **** /* No operators found? Then fail... */ if (clist != NULL) { ! /* ! * Unspecified type for one of the arguments? then use the other ! * (XXX this is probably dead code?) ! */ ! Oid inputOids[2]; ! if (rtypeId == InvalidOid) ! rtypeId = ltypeId; ! else if (ltypeId == InvalidOid) ! ltypeId = rtypeId; ! inputOids[0] = ltypeId; ! inputOids[1] = rtypeId; ! fdresult = oper_select_candidate(2, inputOids, clist, &operOid); } } --- 517,543 ---- /* No operators found? Then fail... */ if (clist != NULL) { ! if (OidIsValid(operOidCache)) ! operOid = operOidCache; ! else ! { ! /* ! * Unspecified type for one of the arguments? then use the other ! * (XXX this is probably dead code?) ! */ ! Oid inputOids[2]; ! ! if (rtypeId == InvalidOid) ! rtypeId = ltypeId; ! else if (ltypeId == InvalidOid) ! ltypeId = rtypeId; ! inputOids[0] = ltypeId; ! inputOids[1] = rtypeId; ! fdresult = oper_select_candidate(2, inputOids, clist, &operOid); ! if (ltypeId == 1043 && rtypeId == 705) ! operOidCache = operOid; ! } } }
\set naccounts 100000 * :scale \setrandom aid 1 :naccounts SELECT abalance FROM accounts WHERE aid = :aid;
\set naccounts 100000 * :scale \setrandom aid 1 :naccounts SELECT abalance FROM av WHERE aid = ':aid';
Index: src/backend/parser/parse_oper.c =================================================================== RCS file: /home/sriggs/pg/REPOSITORY/pgsql/src/backend/parser/parse_oper.c,v retrieving revision 1.98 diff -c -r1.98 parse_oper.c *** src/backend/parser/parse_oper.c 22 Nov 2007 19:40:25 -0000 1.98 --- src/backend/parser/parse_oper.c 26 Nov 2007 23:08:09 -0000 *************** *** 28,33 **** --- 28,34 ---- #include "utils/syscache.h" #include "utils/typcache.h" + oper_select_hook_type oper_select_hook = NULL; static Oid binary_oper_exact(List *opname, Oid arg1, Oid arg2); static FuncDetailCode oper_select_candidate(int nargs, *************** *** 528,534 **** ltypeId = rtypeId; inputOids[0] = ltypeId; inputOids[1] = rtypeId; ! fdresult = oper_select_candidate(2, inputOids, clist, &operOid); } } --- 529,544 ---- ltypeId = rtypeId; inputOids[0] = ltypeId; inputOids[1] = rtypeId; ! ! /* ! * Allow user defined operator selection, allowing hard-coding ! * cacheing or other mechanisms of operator selection for ! * improved performance in certain circumstances ! */ ! if (oper_select_hook) ! fdresult = (* oper_select_hook) (2, inputOids, clist, &operOid); ! else ! fdresult = oper_select_candidate(2, inputOids, clist, &operOid); } } Index: src/include/parser/parse_oper.h =================================================================== RCS file: /home/sriggs/pg/REPOSITORY/pgsql/src/include/parser/parse_oper.h,v retrieving revision 1.41 diff -c -r1.41 parse_oper.h *** src/include/parser/parse_oper.h 5 Jan 2007 22:19:57 -0000 1.41 --- src/include/parser/parse_oper.h 26 Nov 2007 23:03:57 -0000 *************** *** 16,21 **** --- 16,22 ---- #include "access/htup.h" #include "parser/parse_node.h" + #include "parser/parse_func.h" typedef HeapTuple Operator; *************** *** 37,42 **** --- 38,49 ---- extern Operator left_oper(ParseState *pstate, List *op, Oid arg, bool noError, int location); + typedef FuncDetailCode (*oper_select_hook_type) (int nargs, + Oid *input_typeids, + FuncCandidateList candidates, + Oid *operOid); + extern PGDLLIMPORT oper_select_hook_type oper_select_hook; + /* Routines to find operators that DO NOT require coercion --- ie, their */ /* input types are either exactly as given, or binary-compatible */ extern Operator compatible_oper(ParseState *pstate, List *op,
---------------------------(end of broadcast)--------------------------- TIP 6: explain analyze is your friend