|
8 | 8 | *
|
9 | 9 | *
|
10 | 10 | * IDENTIFICATION
|
11 |
| - * $Header: /cvsroot/pgsql/src/backend/optimizer/util/pathnode.c,v 1.84 2003/01/20 18:54:56 tgl Exp $ |
| 11 | + * $Header: /cvsroot/pgsql/src/backend/optimizer/util/pathnode.c,v 1.85 2003/01/22 00:07:00 tgl Exp $ |
12 | 12 | *
|
13 | 13 | *-------------------------------------------------------------------------
|
14 | 14 | */
|
15 | 15 | #include "postgres.h"
|
16 | 16 |
|
17 | 17 | #include <math.h>
|
18 | 18 |
|
| 19 | +#include "catalog/pg_operator.h" |
19 | 20 | #include "executor/executor.h"
|
| 21 | +#include "miscadmin.h" |
20 | 22 | #include "nodes/plannodes.h"
|
21 | 23 | #include "optimizer/cost.h"
|
22 | 24 | #include "optimizer/pathnode.h"
|
23 | 25 | #include "optimizer/paths.h"
|
24 | 26 | #include "optimizer/restrictinfo.h"
|
| 27 | +#include "parser/parse_expr.h" |
| 28 | +#include "parser/parse_oper.h" |
25 | 29 | #include "utils/memutils.h"
|
26 | 30 | #include "utils/selfuncs.h"
|
| 31 | +#include "utils/syscache.h" |
| 32 | + |
| 33 | + |
| 34 | +static bool hash_safe_tlist(List *tlist); |
27 | 35 |
|
28 | 36 |
|
29 | 37 | /*****************************************************************************
|
@@ -506,6 +514,7 @@ create_unique_path(Query *root, RelOptInfo *rel, Path *subpath)
|
506 | 514 | {
|
507 | 515 | UniquePath *pathnode;
|
508 | 516 | Path sort_path; /* dummy for result of cost_sort */
|
| 517 | + Path agg_path; /* dummy for result of cost_agg */ |
509 | 518 | MemoryContext oldcontext;
|
510 | 519 | List *sub_targetlist;
|
511 | 520 | List *l;
|
@@ -587,16 +596,80 @@ create_unique_path(Query *root, RelOptInfo *rel, Path *subpath)
|
587 | 596 | */
|
588 | 597 | sort_path.total_cost += cpu_operator_cost * rel->rows * numCols;
|
589 | 598 |
|
590 |
| - pathnode->use_hash = false; /* for now */ |
| 599 | + /* |
| 600 | + * Is it safe to use a hashed implementation? If so, estimate and |
| 601 | + * compare costs. We only try this if we know the targetlist for |
| 602 | + * sure (else we can't be sure about the datatypes involved). |
| 603 | + */ |
| 604 | + pathnode->use_hash = false; |
| 605 | + if (enable_hashagg && sub_targetlist && hash_safe_tlist(sub_targetlist)) |
| 606 | + { |
| 607 | + /* |
| 608 | + * Estimate the overhead per hashtable entry at 64 bytes (same |
| 609 | + * as in planner.c). |
| 610 | + */ |
| 611 | + int hashentrysize = rel->width + 64; |
591 | 612 |
|
592 |
| - pathnode->path.startup_cost = sort_path.startup_cost; |
593 |
| - pathnode->path.total_cost = sort_path.total_cost; |
| 613 | + if (hashentrysize * pathnode->rows <= SortMem * 1024L) |
| 614 | + { |
| 615 | + cost_agg(&agg_path, root, |
| 616 | + AGG_HASHED, 0, |
| 617 | + numCols, pathnode->rows, |
| 618 | + subpath->startup_cost, |
| 619 | + subpath->total_cost, |
| 620 | + rel->rows); |
| 621 | + if (agg_path.total_cost < sort_path.total_cost) |
| 622 | + pathnode->use_hash = true; |
| 623 | + } |
| 624 | + } |
| 625 | + |
| 626 | + if (pathnode->use_hash) |
| 627 | + { |
| 628 | + pathnode->path.startup_cost = agg_path.startup_cost; |
| 629 | + pathnode->path.total_cost = agg_path.total_cost; |
| 630 | + } |
| 631 | + else |
| 632 | + { |
| 633 | + pathnode->path.startup_cost = sort_path.startup_cost; |
| 634 | + pathnode->path.total_cost = sort_path.total_cost; |
| 635 | + } |
594 | 636 |
|
595 | 637 | rel->cheapest_unique_path = (Path *) pathnode;
|
596 | 638 |
|
597 | 639 | return pathnode;
|
598 | 640 | }
|
599 | 641 |
|
| 642 | +/* |
| 643 | + * hash_safe_tlist - can datatypes of given tlist be hashed? |
| 644 | + * |
| 645 | + * We assume hashed aggregation will work if the datatype's equality operator |
| 646 | + * is marked hashjoinable. |
| 647 | + * |
| 648 | + * XXX this probably should be somewhere else. See also hash_safe_grouping |
| 649 | + * in plan/planner.c. |
| 650 | + */ |
| 651 | +static bool |
| 652 | +hash_safe_tlist(List *tlist) |
| 653 | +{ |
| 654 | + List *tl; |
| 655 | + |
| 656 | + foreach(tl, tlist) |
| 657 | + { |
| 658 | + Node *expr = (Node *) lfirst(tl); |
| 659 | + Operator optup; |
| 660 | + bool oprcanhash; |
| 661 | + |
| 662 | + optup = equality_oper(exprType(expr), true); |
| 663 | + if (!optup) |
| 664 | + return false; |
| 665 | + oprcanhash = ((Form_pg_operator) GETSTRUCT(optup))->oprcanhash; |
| 666 | + ReleaseSysCache(optup); |
| 667 | + if (!oprcanhash) |
| 668 | + return false; |
| 669 | + } |
| 670 | + return true; |
| 671 | +} |
| 672 | + |
600 | 673 | /*
|
601 | 674 | * create_subqueryscan_path
|
602 | 675 | * Creates a path corresponding to a sequential scan of a subquery,
|
|
0 commit comments