Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit50e17ad

Browse files
committed
Speedup ScalarArrayOpExpr evaluation
ScalarArrayOpExprs with "useOr=true" and a set of Consts on the righthandside have traditionally been evaluated by using a linear search over thearray. When these arrays contain large numbers of elements then thislinear search could become a significant part of execution time.Here we add a new method of evaluating ScalarArrayOpExpr expressions toallow them to be evaluated by first building a hash table containing eachelement, then on subsequent evaluations, we just probe that hash table todetermine if there is a match.The planner is in charge of determining when this optimization is possibleand it enables it by setting hashfuncid in the ScalarArrayOpExpr. Theexecutor will only perform the hash table evaluation when the hashfuncidis set.This means that not all cases are optimized. For example CHECK constraintscontaining an IN clause won't go through the planner, so won't get thehashfuncid set. We could maybe do something about that at some laterdate. The reason we're not doing it now is from fear that we may slowdown cases where the expression is evaluated only once. Those cases canbe common, for example, a single row INSERT to a table with a CHECKconstraint containing an IN clause.In the planner, we enable this when there are suitable hash functions forthe ScalarArrayOpExpr's operator and only when there is at leastMIN_ARRAY_SIZE_FOR_HASHED_SAOP elements in the array. The threshold iscurrently set to 9.Author: James Coleman, David RowleyReviewed-by: David Rowley, Tomas Vondra, Heikki LinnakangasDiscussion:https://postgr.es/m/CAAaqYe8x62+=wn0zvNKCj55tPpg-JBHzhZFFc6ANovdqFw7-dA@mail.gmail.com
1 parent1d25757 commit50e17ad

File tree

21 files changed

+712
-30
lines changed

21 files changed

+712
-30
lines changed

‎src/backend/executor/execExpr.c

Lines changed: 81 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1149,6 +1149,8 @@ ExecInitExprRec(Expr *node, ExprState *state,
11491149
FmgrInfo*finfo;
11501150
FunctionCallInfofcinfo;
11511151
AclResultaclresult;
1152+
FmgrInfo*hash_finfo;
1153+
FunctionCallInfohash_fcinfo;
11521154

11531155
Assert(list_length(opexpr->args)==2);
11541156
scalararg= (Expr*)linitial(opexpr->args);
@@ -1163,6 +1165,17 @@ ExecInitExprRec(Expr *node, ExprState *state,
11631165
get_func_name(opexpr->opfuncid));
11641166
InvokeFunctionExecuteHook(opexpr->opfuncid);
11651167

1168+
if (OidIsValid(opexpr->hashfuncid))
1169+
{
1170+
aclresult=pg_proc_aclcheck(opexpr->hashfuncid,
1171+
GetUserId(),
1172+
ACL_EXECUTE);
1173+
if (aclresult!=ACLCHECK_OK)
1174+
aclcheck_error(aclresult,OBJECT_FUNCTION,
1175+
get_func_name(opexpr->hashfuncid));
1176+
InvokeFunctionExecuteHook(opexpr->hashfuncid);
1177+
}
1178+
11661179
/* Set up the primary fmgr lookup information */
11671180
finfo=palloc0(sizeof(FmgrInfo));
11681181
fcinfo=palloc0(SizeForFunctionCallInfo(2));
@@ -1171,26 +1184,76 @@ ExecInitExprRec(Expr *node, ExprState *state,
11711184
InitFunctionCallInfoData(*fcinfo,finfo,2,
11721185
opexpr->inputcollid,NULL,NULL);
11731186

1174-
/* Evaluate scalar directly into left function argument */
1175-
ExecInitExprRec(scalararg,state,
1176-
&fcinfo->args[0].value,&fcinfo->args[0].isnull);
1177-
11781187
/*
1179-
* Evaluate array argument into our return value. There's no
1180-
* danger in that, because the return value is guaranteed to
1181-
* be overwritten by EEOP_SCALARARRAYOP, and will not be
1182-
* passed to any other expression.
1188+
* If hashfuncid is set, we create a EEOP_HASHED_SCALARARRAYOP
1189+
* step instead of a EEOP_SCALARARRAYOP. This provides much
1190+
* faster lookup performance than the normal linear search
1191+
* when the number of items in the array is anything but very
1192+
* small.
11831193
*/
1184-
ExecInitExprRec(arrayarg,state,resv,resnull);
1185-
1186-
/* And perform the operation */
1187-
scratch.opcode=EEOP_SCALARARRAYOP;
1188-
scratch.d.scalararrayop.element_type=InvalidOid;
1189-
scratch.d.scalararrayop.useOr=opexpr->useOr;
1190-
scratch.d.scalararrayop.finfo=finfo;
1191-
scratch.d.scalararrayop.fcinfo_data=fcinfo;
1192-
scratch.d.scalararrayop.fn_addr=finfo->fn_addr;
1193-
ExprEvalPushStep(state,&scratch);
1194+
if (OidIsValid(opexpr->hashfuncid))
1195+
{
1196+
hash_finfo=palloc0(sizeof(FmgrInfo));
1197+
hash_fcinfo=palloc0(SizeForFunctionCallInfo(1));
1198+
fmgr_info(opexpr->hashfuncid,hash_finfo);
1199+
fmgr_info_set_expr((Node*)node,hash_finfo);
1200+
InitFunctionCallInfoData(*hash_fcinfo,hash_finfo,
1201+
1,opexpr->inputcollid,NULL,
1202+
NULL);
1203+
1204+
scratch.d.hashedscalararrayop.hash_finfo=hash_finfo;
1205+
scratch.d.hashedscalararrayop.hash_fcinfo_data=hash_fcinfo;
1206+
scratch.d.hashedscalararrayop.hash_fn_addr=hash_finfo->fn_addr;
1207+
1208+
/* Evaluate scalar directly into left function argument */
1209+
ExecInitExprRec(scalararg,state,
1210+
&fcinfo->args[0].value,&fcinfo->args[0].isnull);
1211+
1212+
/*
1213+
* Evaluate array argument into our return value. There's
1214+
* no danger in that, because the return value is
1215+
* guaranteed to be overwritten by
1216+
* EEOP_HASHED_SCALARARRAYOP, and will not be passed to
1217+
* any other expression.
1218+
*/
1219+
ExecInitExprRec(arrayarg,state,resv,resnull);
1220+
1221+
/* And perform the operation */
1222+
scratch.opcode=EEOP_HASHED_SCALARARRAYOP;
1223+
scratch.d.hashedscalararrayop.finfo=finfo;
1224+
scratch.d.hashedscalararrayop.fcinfo_data=fcinfo;
1225+
scratch.d.hashedscalararrayop.fn_addr=finfo->fn_addr;
1226+
1227+
scratch.d.hashedscalararrayop.hash_finfo=hash_finfo;
1228+
scratch.d.hashedscalararrayop.hash_fcinfo_data=hash_fcinfo;
1229+
scratch.d.hashedscalararrayop.hash_fn_addr=hash_finfo->fn_addr;
1230+
1231+
ExprEvalPushStep(state,&scratch);
1232+
}
1233+
else
1234+
{
1235+
/* Evaluate scalar directly into left function argument */
1236+
ExecInitExprRec(scalararg,state,
1237+
&fcinfo->args[0].value,
1238+
&fcinfo->args[0].isnull);
1239+
1240+
/*
1241+
* Evaluate array argument into our return value. There's
1242+
* no danger in that, because the return value is
1243+
* guaranteed to be overwritten by EEOP_SCALARARRAYOP, and
1244+
* will not be passed to any other expression.
1245+
*/
1246+
ExecInitExprRec(arrayarg,state,resv,resnull);
1247+
1248+
/* And perform the operation */
1249+
scratch.opcode=EEOP_SCALARARRAYOP;
1250+
scratch.d.scalararrayop.element_type=InvalidOid;
1251+
scratch.d.scalararrayop.useOr=opexpr->useOr;
1252+
scratch.d.scalararrayop.finfo=finfo;
1253+
scratch.d.scalararrayop.fcinfo_data=fcinfo;
1254+
scratch.d.scalararrayop.fn_addr=finfo->fn_addr;
1255+
ExprEvalPushStep(state,&scratch);
1256+
}
11941257
break;
11951258
}
11961259

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp