15
15
*
16
16
*
17
17
* 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 $
19
19
*
20
20
*-------------------------------------------------------------------------
21
21
*/
@@ -1394,7 +1394,6 @@ scalararraysel(PlannerInfo *root,
1394
1394
{
1395
1395
oprsel = get_oprjoin (operator );
1396
1396
selarg4 = Int16GetDatum (jointype );
1397
-
1398
1397
}
1399
1398
else
1400
1399
{
@@ -1519,6 +1518,7 @@ scalararraysel(PlannerInfo *root,
1519
1518
s1 = useOr ? 0.0 : 1.0 ;
1520
1519
/*
1521
1520
* Arbitrarily assume 10 elements in the eventual array value
1521
+ * (see also estimate_array_length)
1522
1522
*/
1523
1523
for (i = 0 ; i < 10 ; i ++ )
1524
1524
{
@@ -1535,6 +1535,37 @@ scalararraysel(PlannerInfo *root,
1535
1535
return s1 ;
1536
1536
}
1537
1537
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
+
1538
1569
/*
1539
1570
* rowcomparesel - Selectivity of RowCompareExpr Node.
1540
1571
*
@@ -4473,10 +4504,14 @@ genericcostestimate(PlannerInfo *root,
4473
4504
double * indexCorrelation )
4474
4505
{
4475
4506
double numIndexPages ;
4507
+ double num_sa_scans ;
4508
+ double num_outer_scans ;
4509
+ double num_scans ;
4476
4510
QualCost index_qual_cost ;
4477
4511
double qual_op_cost ;
4478
4512
double qual_arg_cost ;
4479
4513
List * selectivityQuals ;
4514
+ ListCell * l ;
4480
4515
4481
4516
/*
4482
4517
* If the index is partial, AND the index predicate with the explicitly
@@ -4513,6 +4548,25 @@ genericcostestimate(PlannerInfo *root,
4513
4548
else
4514
4549
selectivityQuals = indexQuals ;
4515
4550
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
+
4516
4570
/* Estimate the fraction of main-table tuples that will be visited */
4517
4571
* indexSelectivity = clauselist_selectivity (root , selectivityQuals ,
4518
4572
index -> rel -> relid ,
@@ -4527,8 +4581,15 @@ genericcostestimate(PlannerInfo *root,
4527
4581
numIndexTuples = * indexSelectivity * index -> rel -> tuples ;
4528
4582
4529
4583
/*
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
4532
4593
* indexSelectivity estimate is tiny.
4533
4594
*/
4534
4595
if (numIndexTuples > index -> tuples )
@@ -4556,7 +4617,8 @@ genericcostestimate(PlannerInfo *root,
4556
4617
*
4557
4618
* The above calculations are all per-index-scan. However, if we are
4558
4619
* 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
4560
4622
* creates the potential for cache effects to reduce the number of
4561
4623
* disk page fetches needed. We want to estimate the average per-scan
4562
4624
* I/O cost in the presence of caching.
@@ -4569,7 +4631,17 @@ genericcostestimate(PlannerInfo *root,
4569
4631
*/
4570
4632
if (outer_rel != NULL && outer_rel -> rows > 1 )
4571
4633
{
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
+ {
4573
4645
double pages_fetched ;
4574
4646
4575
4647
/* total page fetches ignoring cache effects */
@@ -4582,9 +4654,10 @@ genericcostestimate(PlannerInfo *root,
4582
4654
4583
4655
/*
4584
4656
* 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.)
4586
4659
*/
4587
- * indexTotalCost = (pages_fetched * random_page_cost ) / num_scans ;
4660
+ * indexTotalCost = (pages_fetched * random_page_cost ) / num_outer_scans ;
4588
4661
}
4589
4662
else
4590
4663
{
0 commit comments