1515 *
1616 *
1717 * IDENTIFICATION
18- * $PostgreSQL: pgsql/src/backend/utils/adt/selfuncs.c,v 1.207 2006/06/06 17:59:57 tgl Exp $
18+ * $PostgreSQL: pgsql/src/backend/utils/adt/selfuncs.c,v 1.208 2006/07/01 22:07:23 tgl Exp $
1919 *
2020 *-------------------------------------------------------------------------
2121 */
@@ -1394,7 +1394,6 @@ scalararraysel(PlannerInfo *root,
13941394{
13951395oprsel = get_oprjoin (operator );
13961396selarg4 = Int16GetDatum (jointype );
1397-
13981397}
13991398else
14001399{
@@ -1519,6 +1518,7 @@ scalararraysel(PlannerInfo *root,
15191518s1 = useOr ?0.0 :1.0 ;
15201519/*
15211520 * Arbitrarily assume 10 elements in the eventual array value
1521+ * (see also estimate_array_length)
15221522 */
15231523for (i = 0 ;i < 10 ;i ++ )
15241524{
@@ -1535,6 +1535,37 @@ scalararraysel(PlannerInfo *root,
15351535return s1 ;
15361536}
15371537
1538+ /*
1539+ * Estimate number of elements in the array yielded by an expression.
1540+ *
1541+ * It's important that this agree with scalararraysel.
1542+ */
1543+ int
1544+ estimate_array_length (Node * arrayexpr )
1545+ {
1546+ if (arrayexpr && IsA (arrayexpr ,Const ))
1547+ {
1548+ Datum arraydatum = ((Const * )arrayexpr )-> constvalue ;
1549+ bool arrayisnull = ((Const * )arrayexpr )-> constisnull ;
1550+ ArrayType * arrayval ;
1551+
1552+ if (arrayisnull )
1553+ return 0 ;
1554+ arrayval = DatumGetArrayTypeP (arraydatum );
1555+ return ArrayGetNItems (ARR_NDIM (arrayval ),ARR_DIMS (arrayval ));
1556+ }
1557+ else if (arrayexpr && IsA (arrayexpr ,ArrayExpr )&&
1558+ !((ArrayExpr * )arrayexpr )-> multidims )
1559+ {
1560+ return list_length (((ArrayExpr * )arrayexpr )-> elements );
1561+ }
1562+ else
1563+ {
1564+ /* default guess --- see also scalararraysel */
1565+ return 10 ;
1566+ }
1567+ }
1568+
15381569/*
15391570 *rowcomparesel- Selectivity of RowCompareExpr Node.
15401571 *
@@ -4473,10 +4504,14 @@ genericcostestimate(PlannerInfo *root,
44734504double * indexCorrelation )
44744505{
44754506double numIndexPages ;
4507+ double num_sa_scans ;
4508+ double num_outer_scans ;
4509+ double num_scans ;
44764510QualCost index_qual_cost ;
44774511double qual_op_cost ;
44784512double qual_arg_cost ;
44794513List * selectivityQuals ;
4514+ ListCell * l ;
44804515
44814516/*
44824517 * If the index is partial, AND the index predicate with the explicitly
@@ -4513,6 +4548,25 @@ genericcostestimate(PlannerInfo *root,
45134548else
45144549selectivityQuals = indexQuals ;
45154550
4551+ /*
4552+ * Check for ScalarArrayOpExpr index quals, and estimate the number
4553+ * of index scans that will be performed.
4554+ */
4555+ num_sa_scans = 1 ;
4556+ foreach (l ,indexQuals )
4557+ {
4558+ RestrictInfo * rinfo = (RestrictInfo * )lfirst (l );
4559+
4560+ if (IsA (rinfo -> clause ,ScalarArrayOpExpr ))
4561+ {
4562+ ScalarArrayOpExpr * saop = (ScalarArrayOpExpr * )rinfo -> clause ;
4563+ int alength = estimate_array_length (lsecond (saop -> args ));
4564+
4565+ if (alength > 1 )
4566+ num_sa_scans *=alength ;
4567+ }
4568+ }
4569+
45164570/* Estimate the fraction of main-table tuples that will be visited */
45174571* indexSelectivity = clauselist_selectivity (root ,selectivityQuals ,
45184572index -> rel -> relid ,
@@ -4527,8 +4581,15 @@ genericcostestimate(PlannerInfo *root,
45274581numIndexTuples = * indexSelectivity * index -> rel -> tuples ;
45284582
45294583/*
4530- * We can bound the number of tuples by the index size in any case. Also,
4531- * always estimate at least one tuple is touched, even when
4584+ * The estimate obtained so far counts all the tuples returned by all
4585+ * scans of ScalarArrayOpExpr calls. We want to consider the per-scan
4586+ * number, so adjust. This is a handy place to round to integer, too.
4587+ */
4588+ numIndexTuples = rint (numIndexTuples /num_sa_scans );
4589+
4590+ /*
4591+ * We can bound the number of tuples by the index size in any case.
4592+ * Also, always estimate at least one tuple is touched, even when
45324593 * indexSelectivity estimate is tiny.
45334594 */
45344595if (numIndexTuples > index -> tuples )
@@ -4556,7 +4617,8 @@ genericcostestimate(PlannerInfo *root,
45564617 *
45574618 * The above calculations are all per-index-scan. However, if we are
45584619 * in a nestloop inner scan, we can expect the scan to be repeated (with
4559- * different search keys) for each row of the outer relation. This
4620+ * different search keys) for each row of the outer relation. Likewise,
4621+ * ScalarArrayOpExpr quals result in multiple index scans. This
45604622 * creates the potential for cache effects to reduce the number of
45614623 * disk page fetches needed. We want to estimate the average per-scan
45624624 * I/O cost in the presence of caching.
@@ -4569,7 +4631,17 @@ genericcostestimate(PlannerInfo *root,
45694631 */
45704632if (outer_rel != NULL && outer_rel -> rows > 1 )
45714633{
4572- double num_scans = outer_rel -> rows ;
4634+ num_outer_scans = outer_rel -> rows ;
4635+ num_scans = num_sa_scans * num_outer_scans ;
4636+ }
4637+ else
4638+ {
4639+ num_outer_scans = 1 ;
4640+ num_scans = num_sa_scans ;
4641+ }
4642+
4643+ if (num_scans > 1 )
4644+ {
45734645double pages_fetched ;
45744646
45754647/* total page fetches ignoring cache effects */
@@ -4582,9 +4654,10 @@ genericcostestimate(PlannerInfo *root,
45824654
45834655/*
45844656 * Now compute the total disk access cost, and then report a
4585- * pro-rated share for one index scan.
4657+ * pro-rated share for each outer scan. (Don't pro-rate for
4658+ * ScalarArrayOpExpr, since that's internal to the indexscan.)
45864659 */
4587- * indexTotalCost = (pages_fetched * random_page_cost ) /num_scans ;
4660+ * indexTotalCost = (pages_fetched * random_page_cost ) /num_outer_scans ;
45884661}
45894662else
45904663{