forked from huawei/openGauss-server
回合路径生唯一索引优先,多列主键选择率估算错误,无法禁止索引扫描,修正索引代价模型
This commit is contained in:
parent
ee30a37bb3
commit
424b1c0b79
|
|
@ -653,7 +653,7 @@ enable_auto_explain|bool|0,0|NULL|NULL|
|
|||
auto_explain_level|enum|off,log,notice|NULL|NULL|
|
||||
cost_weight_index|real|1e-10,1e+10|NULL|NULL|
|
||||
default_limit_rows|real|-100,1.79769e+308|NULL|NULL|
|
||||
sql_beta_feature|enum|sel_semi_poisson,sel_expr_instr,param_path_gen,rand_cost_opt,param_path_opt,page_est_opt,none|NULL|NULL|
|
||||
sql_beta_feature|enum|no_unique_index_first,sel_semi_poisson,sel_expr_instr,param_path_gen,rand_cost_opt,param_path_opt,page_est_opt,none|NULL|NULL|
|
||||
xlog_idle_flushes_before_sleep|int64|0,576460752303423487|NULL|NULL|
|
||||
wal_writer_cpu|int|-1,2147483647|NULL|NULL|
|
||||
wal_file_init_num|int|1,2147483647|NULL|NULL|
|
||||
|
|
|
|||
|
|
@ -993,6 +993,7 @@ static const struct config_enum_entry sql_beta_options[] = {
|
|||
{"rand_cost_opt", RAND_COST_OPT, false},
|
||||
{"page_est_opt", PAGE_EST_OPT, false},
|
||||
{"param_path_opt", PARAM_PATH_OPT, false},
|
||||
{"no_unique_index_first", NO_UNIQUE_INDEX_FIRST, false},
|
||||
{NULL, 0, false}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1246,6 +1246,13 @@ void cost_index(IndexPath* path, PlannerInfo* root, double loop_count)
|
|||
min_IO_cost = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* When database keep running without vacuum, the number of relpages may inflate quickly
|
||||
* and finally cause min_IO_cost overestimated. So, adjust min_IO_cost to ensure
|
||||
* min_IO_cost < max_IO_cost.
|
||||
*/
|
||||
min_IO_cost = Min(min_IO_cost, max_IO_cost);
|
||||
|
||||
ereport(DEBUG2,
|
||||
(errmodule(MOD_OPT),
|
||||
errmsg("Computing IndexScanCost(loop_count = 1): min_pages_fetched: %lf, min_IO_cost: %lf",
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ const int TOW_MEMBERS = 2;
|
|||
|
||||
ES_SELECTIVITY::ES_SELECTIVITY()
|
||||
: es_candidate_list(NULL),
|
||||
es_candidate_saved(NULL),
|
||||
unmatched_clause_group(NULL),
|
||||
root(NULL),
|
||||
sjinfo(NULL),
|
||||
|
|
@ -41,6 +42,63 @@ ES_SELECTIVITY::ES_SELECTIVITY()
|
|||
ES_SELECTIVITY::~ES_SELECTIVITY()
|
||||
{}
|
||||
|
||||
bool ES_SELECTIVITY::ContainIndexCols(const es_candidate* es, const IndexOptInfo* index) const
|
||||
{
|
||||
for (int pos = 0; pos < index->ncolumns; pos++) {
|
||||
int indexAttNum = index->indexkeys[pos];
|
||||
/*
|
||||
* Notice: indexAttNum can be negative. Some indexAttNums of junk column may be negative
|
||||
* since they are located before the first visible column. for example, the indexAttNum
|
||||
* of 'oid' column in system table 'pg_class' is -2.
|
||||
*/
|
||||
if (indexAttNum >= 0 && !bms_is_member(indexAttNum, es->left_attnums))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ES_SELECTIVITY::MatchUniqueIndex(const es_candidate* es) const
|
||||
{
|
||||
ListCell* lci = NULL;
|
||||
foreach (lci, es->left_rel->indexlist) {
|
||||
IndexOptInfo* indexToMatch = (IndexOptInfo*)lfirst(lci);
|
||||
if (indexToMatch->relam == BTREE_AM_OID && indexToMatch->unique
|
||||
&& ContainIndexCols(es, indexToMatch)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* check whether the equality constraints match an unique index.
|
||||
* We know the result only has one row if finding a matched unique index.
|
||||
*/
|
||||
void ES_SELECTIVITY::CalSelWithUniqueIndex(Selectivity &result)
|
||||
{
|
||||
List* es_candidate_used = NULL;
|
||||
ListCell* l = NULL;
|
||||
foreach(l, es_candidate_list) {
|
||||
es_candidate* temp = (es_candidate*)lfirst(l);
|
||||
if (temp->tag == ES_EQSEL && MatchUniqueIndex(temp) &&
|
||||
temp->left_rel && temp->left_rel->tuples >= 1.0) {
|
||||
result *= 1.0 / temp->left_rel->tuples;
|
||||
es_candidate_used = lappend(es_candidate_used, temp);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Finally, we need to delete es_candidates which have already used. The rests es_candidates
|
||||
* will calculate with statistic info.
|
||||
*/
|
||||
es_candidate_saved = es_candidate_list;
|
||||
es_candidate_list = list_difference(es_candidate_list, es_candidate_used);
|
||||
|
||||
list_free(es_candidate_used);
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief Main entry for using extended statistic to calculate selectivity
|
||||
* root_input can only be NULL when processing group by clauses
|
||||
|
|
@ -62,6 +120,12 @@ Selectivity ES_SELECTIVITY::calculate_selectivity(PlannerInfo* root_input, List*
|
|||
group_clauselist(origin_clauses);
|
||||
}
|
||||
|
||||
/*
|
||||
* Before reading statistic, We check whether the equality constraints match an
|
||||
* unique index. We know the result only has one row if finding a matched unique index.
|
||||
*/
|
||||
CalSelWithUniqueIndex(result);
|
||||
|
||||
/* read statistic */
|
||||
read_statistic();
|
||||
|
||||
|
|
@ -91,6 +155,8 @@ Selectivity ES_SELECTIVITY::calculate_selectivity(PlannerInfo* root_input, List*
|
|||
}
|
||||
}
|
||||
|
||||
es_candidate_list = es_candidate_saved;
|
||||
|
||||
/* free memory, but unmatched_clause_group need to be free manually */
|
||||
clear();
|
||||
|
||||
|
|
@ -589,7 +655,7 @@ static bool ClauseIsLegal(es_type type, const Node* left, const Node* right, int
|
|||
/* check clause type */
|
||||
switch (type) {
|
||||
case ES_EQSEL:
|
||||
if (!IsA(left, Const) && !IsA(right, Const))
|
||||
if (!IsA(left, Const) && !IsA(right, Const) && !IsA(left, Param) && !IsA(right, Param))
|
||||
return false;
|
||||
else if (IsA(left, Const) && ((Const*)left)->constisnull)
|
||||
return false;
|
||||
|
|
@ -1251,7 +1317,7 @@ int ES_SELECTIVITY::read_attnum(Node* node) const
|
|||
attnum = var->varattno;
|
||||
if (attnum <= 0)
|
||||
attnum = -1;
|
||||
} else if (IsA(node, Const))
|
||||
} else if (IsA(node, Const) || IsA(node, Param))
|
||||
attnum = 0;
|
||||
|
||||
return attnum;
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
#include "catalog/pg_operator.h"
|
||||
#include "catalog/pg_opfamily.h"
|
||||
#include "catalog/pg_type.h"
|
||||
#include "catalog/pg_proc.h"
|
||||
#include "nodes/makefuncs.h"
|
||||
#include "optimizer/clauses.h"
|
||||
#include "optimizer/cost.h"
|
||||
|
|
@ -725,6 +726,67 @@ static inline bool index_relation_has_bucket(IndexOptInfo* index)
|
|||
return hasBucket;
|
||||
}
|
||||
|
||||
inline bool IsEqRestrict(const RestrictInfo* rinfo)
|
||||
{
|
||||
Expr* clause = rinfo->clause;
|
||||
return is_opclause(clause) && get_oprrest(((OpExpr*)clause)->opno) == EQSELRETURNOID;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check whether the indexqualcols in indexpath contain the given attNum and the
|
||||
* constraint condition on this attNum is equality constraints.
|
||||
*/
|
||||
inline bool HasAttNumAndEqRestrict(const IndexPath* newPath, const int attNum)
|
||||
{
|
||||
ListCell* lc1 = NULL;
|
||||
ListCell* lc2 = NULL;
|
||||
IndexOptInfo* newPathIndex = (IndexOptInfo*)newPath->indexinfo;
|
||||
forboth (lc1, newPath->indexqualcols, lc2, newPath->indexquals) {
|
||||
int i = lfirst_int(lc1);
|
||||
RestrictInfo* rinfo = (RestrictInfo*)lfirst(lc2);
|
||||
if (newPathIndex->indexkeys[i] == attNum && IsEqRestrict(rinfo))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check whether index path contain all the index columns and the constraint conditions
|
||||
* are equality constraints.
|
||||
*/
|
||||
inline bool ContainAllColsAndEqRestrict(const IndexPath* newPath, const IndexOptInfo* index)
|
||||
{
|
||||
for (int pos = 0; pos < index->ncolumns; pos++) {
|
||||
if (!HasAttNumAndEqRestrict(newPath, index->indexkeys[pos]))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* For the given index, we want to mark whether the index contains the columns come from an
|
||||
* unique index and the constraint conditions on these columns are equality constraints. This
|
||||
* mark will be used in unique index first rule during path generation.
|
||||
*/
|
||||
void MarkUniqueIndexFirstRule(const RelOptInfo* rel, const IndexOptInfo* index, List* result)
|
||||
{
|
||||
if (!ENABLE_SQL_BETA_FEATURE(NO_UNIQUE_INDEX_FIRST) && index->relam == BTREE_AM_OID) {
|
||||
ListCell* lcr = NULL;
|
||||
foreach (lcr, result) {
|
||||
IndexPath* newPath = (IndexPath*)lfirst(lcr);
|
||||
ListCell* lci = NULL;
|
||||
foreach (lci, rel->indexlist) {
|
||||
IndexOptInfo* indexToMatch = (IndexOptInfo*)lfirst(lci);
|
||||
if (indexToMatch->relam == BTREE_AM_OID && indexToMatch->unique &&
|
||||
ContainAllColsAndEqRestrict(newPath, indexToMatch)) {
|
||||
newPath->rulesforindexgen |= BTREE_INDEX_CONTAIN_UNIQUE_COLS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* build_index_paths
|
||||
* Given an index and a set of index clauses for it, construct zero
|
||||
|
|
@ -964,6 +1026,13 @@ static List* build_index_paths(PlannerInfo* root, RelOptInfo* rel, IndexOptInfo*
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 6. Mark whether unique index fisrt rule satisfied in current btree index path.
|
||||
* The rules will be used for selecting paths. We will check whether current index path
|
||||
* contains a unique btree columns and the constraint conditions are equality constraints.
|
||||
*/
|
||||
MarkUniqueIndexFirstRule(rel, index, result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -253,6 +253,134 @@ PathCostComparison compare_join_single_node_distribution(Path* path1, Path* path
|
|||
return COSTS_DIFFERENT;
|
||||
}
|
||||
|
||||
inline bool IsSeqScanPath(const Path* path)
|
||||
{
|
||||
return path->pathtype == T_SeqScan;
|
||||
}
|
||||
|
||||
inline bool IsBtreeIndexPath(const Path* path)
|
||||
{
|
||||
return path->type == T_IndexPath &&
|
||||
((IndexPath*)path)->indexinfo->relam == BTREE_AM_OID;
|
||||
}
|
||||
|
||||
inline bool AreTwoBtreeIdxPaths(const Path* path1, const Path* path2)
|
||||
{
|
||||
return IsBtreeIndexPath(path1) && IsBtreeIndexPath(path2);
|
||||
}
|
||||
|
||||
inline bool IsBtreeIdxAndSeqPath(const Path* path1, const Path* path2)
|
||||
{
|
||||
return (IsBtreeIndexPath(path1) && IsSeqScanPath(path2)) ||
|
||||
(IsBtreeIndexPath(path2) && IsSeqScanPath(path1));
|
||||
}
|
||||
|
||||
inline bool IsParamPath(const Path* path)
|
||||
{
|
||||
return path->param_info != NULL;
|
||||
}
|
||||
|
||||
inline bool BothParamPathOrBothNot(const Path* path1, const Path* path2)
|
||||
{
|
||||
return (IsParamPath(path1) && IsParamPath(path2)) ||
|
||||
(!IsParamPath(path1) && !IsParamPath(path2));
|
||||
}
|
||||
|
||||
inline bool ContainUniqueCols(const IndexPath* path)
|
||||
{
|
||||
return path->rulesforindexgen & BTREE_INDEX_CONTAIN_UNIQUE_COLS;
|
||||
}
|
||||
|
||||
/*
|
||||
* The main entry for unique index first rule.
|
||||
* In this rule, we check two aspects:
|
||||
* 1. For Btree index pathA and pathB, pathA contains a unique btree columns and the constraint
|
||||
* conditions are equality constraints. We prefer pathA.
|
||||
* Notice: Only consider unique index first rule when the two index paths are both parameterized path
|
||||
* or both not.
|
||||
* 2. For Btree index pathA and SeqScan pathB, pathA contains a unique btree columns and the constraint
|
||||
* conditions are equality constraints. We prefer pathA.
|
||||
* Notice: This rule is vaild when Btree index pathA is unparameterized path.
|
||||
*/
|
||||
bool ImplementUniqueIndexRule(const Path* path1, const Path* path2, PathCostComparison &cost_comparison)
|
||||
{
|
||||
/* Check the first aspect */
|
||||
if (AreTwoBtreeIdxPaths(path1, path2) && BothParamPathOrBothNot(path1, path2)) {
|
||||
bool path1ContainUniqueCols = ContainUniqueCols((IndexPath*)path1);
|
||||
bool path2ContainUniqueCols = ContainUniqueCols((IndexPath*)path2);
|
||||
/* Compare with 1 to verify whether one path satisfy unique index first rule and another don't. */
|
||||
if (path1ContainUniqueCols + path2ContainUniqueCols == 1) {
|
||||
const int suppressionParam = g_instance.cost_cxt.disable_cost_enlarge_factor;
|
||||
if (path1ContainUniqueCols == true && path1->total_cost < suppressionParam * path2->total_cost) {
|
||||
cost_comparison = COSTS_BETTER1;
|
||||
return true;
|
||||
} else if (path2ContainUniqueCols == true && path2->total_cost < suppressionParam * path1->total_cost) {
|
||||
cost_comparison = COSTS_BETTER2;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Check the second aspect */
|
||||
if (IsBtreeIdxAndSeqPath(path1, path2)) {
|
||||
const int suppressionParam = g_instance.cost_cxt.disable_cost_enlarge_factor;
|
||||
if (IsSeqScanPath(path1) && !IsParamPath(path2) && ContainUniqueCols((IndexPath*)path2) &&
|
||||
path2->total_cost < suppressionParam * path1->total_cost) {
|
||||
cost_comparison = COSTS_BETTER2;
|
||||
return true;
|
||||
} else if (IsSeqScanPath(path2) && !IsParamPath(path1) && ContainUniqueCols((IndexPath*)path1) &&
|
||||
path1->total_cost < suppressionParam * path2->total_cost) {
|
||||
cost_comparison = COSTS_BETTER1;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void DebugPrintUniqueIndexFirstInfo(const Path* path1, const Path* path2, const PathCostComparison &cost_comparison)
|
||||
{
|
||||
char* preferIndexName = NULL;
|
||||
char* ruledOutIndexName = NULL;
|
||||
|
||||
if (cost_comparison == COSTS_BETTER1) {
|
||||
preferIndexName = get_rel_name(((IndexPath*)path1)->indexinfo->indexoid);
|
||||
ruledOutIndexName = IsBtreeIndexPath(path2) ? get_rel_name(((IndexPath*)path2)->indexinfo->indexoid) : NULL;
|
||||
} else {
|
||||
preferIndexName = get_rel_name(((IndexPath*)path2)->indexinfo->indexoid);
|
||||
ruledOutIndexName = IsBtreeIndexPath(path1) ? get_rel_name(((IndexPath*)path1)->indexinfo->indexoid) : NULL;
|
||||
}
|
||||
|
||||
/* ruledOutIndexName = NULL means the ruled out path is a seqscan path. */
|
||||
if (ruledOutIndexName == NULL) {
|
||||
ereport(DEBUG1,
|
||||
(errmodule(MOD_OPT),
|
||||
errmsg("Implement Unique Index rule in selecting path: prefer to use index: %s, rule out seqscan.",
|
||||
preferIndexName)));
|
||||
} else {
|
||||
ereport(DEBUG1,
|
||||
(errmodule(MOD_OPT),
|
||||
errmsg("Implement Unique Index rule in selecting path: prefer to use index: %s, rule out index: %s.",
|
||||
preferIndexName, ruledOutIndexName)));
|
||||
}
|
||||
|
||||
pfree_ext(preferIndexName);
|
||||
pfree_ext(ruledOutIndexName);
|
||||
}
|
||||
|
||||
/* Check whether unique index first rule can be used */
|
||||
bool CheckUniqueIndexFirstRule(const Path* path1, const Path* path2, PathCostComparison &cost_comparison)
|
||||
{
|
||||
if (!ENABLE_SQL_BETA_FEATURE(NO_UNIQUE_INDEX_FIRST) && ImplementUniqueIndexRule(path1, path2, cost_comparison)) {
|
||||
if (log_min_messages <= DEBUG1)
|
||||
DebugPrintUniqueIndexFirstInfo(path1, path2, cost_comparison);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* compare_path_costs_fuzzily
|
||||
* Compare the costs of two paths to see if either can be said to
|
||||
|
|
@ -282,8 +410,18 @@ PathCostComparison compare_path_costs_fuzzily(Path* path1, Path* path2, double f
|
|||
else if (path1->hint_value < path2->hint_value)
|
||||
return COSTS_BETTER2;
|
||||
|
||||
PathCostComparison cost_comparison;
|
||||
|
||||
/*
|
||||
* For index paths, we check if rules can be used to filter.
|
||||
* Here, we tend to select path containing unique index columns.
|
||||
*/
|
||||
if (CheckUniqueIndexFirstRule(path1, path2, cost_comparison)) {
|
||||
return cost_comparison;
|
||||
}
|
||||
|
||||
/* dn gather RBO */
|
||||
PathCostComparison cost_comparison = compare_join_single_node_distribution(path1, path2);
|
||||
cost_comparison = compare_join_single_node_distribution(path1, path2);
|
||||
if (cost_comparison != COSTS_DIFFERENT) {
|
||||
return cost_comparison;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,6 +31,11 @@
|
|||
*/
|
||||
typedef enum CostSelector { STARTUP_COST, TOTAL_COST } CostSelector;
|
||||
|
||||
/* Different rules are used for path generation */
|
||||
typedef enum {
|
||||
NO_PATH_GEN_RULE = 0,
|
||||
BTREE_INDEX_CONTAIN_UNIQUE_COLS = 1 /* an equivalence constraint btree index scan contains unique cols */
|
||||
} RulesForPathGen;
|
||||
/*
|
||||
* The cost estimate produced by cost_qual_eval() includes both a one-time
|
||||
* (startup) cost, and a per-tuple cost.
|
||||
|
|
@ -971,6 +976,10 @@ typedef struct Path {
|
|||
* ORDER BY expression is meant to be used with. (There is no restriction
|
||||
* on which index column each ORDER BY can be used with.)
|
||||
*
|
||||
* 'rulesforindexgen' is a bitmapset. It is used for recording some rules which
|
||||
* are satisfied in current index path. These recorded rules will be used for
|
||||
* filtering paths. We can consider it as the supplement of CBO (cost based optimize).
|
||||
*
|
||||
* 'indexscandir' is one of:
|
||||
* ForwardScanDirection: forward scan of an ordered index
|
||||
* BackwardScanDirection: backward scan of an ordered index
|
||||
|
|
@ -993,6 +1002,7 @@ typedef struct IndexPath {
|
|||
List* indexqualcols;
|
||||
List* indexorderbys;
|
||||
List* indexorderbycols;
|
||||
int rulesforindexgen = NO_PATH_GEN_RULE;
|
||||
ScanDirection indexscandir;
|
||||
Cost indextotalcost;
|
||||
Selectivity indexselectivity;
|
||||
|
|
|
|||
|
|
@ -251,6 +251,7 @@ struct es_candidate {
|
|||
class ES_SELECTIVITY : public BaseObject {
|
||||
public:
|
||||
List* es_candidate_list;
|
||||
List* es_candidate_saved; /* temporarily save es_candidate_list */
|
||||
List* unmatched_clause_group;
|
||||
PlannerInfo* root; /* root from input */
|
||||
SpecialJoinInfo* sjinfo; /* sjinfo from input */
|
||||
|
|
@ -289,8 +290,10 @@ private:
|
|||
Selectivity cal_eqjoinsel_semi(es_candidate* es, RelOptInfo* inner_rel, bool inner_on_left);
|
||||
void cal_stadistinct_eqsel(es_candidate* es);
|
||||
bool cal_stadistinct_eqjoinsel(es_candidate* es);
|
||||
void CalSelWithUniqueIndex(Selectivity &result);
|
||||
void clear_extended_stats(ExtendedStats* extended_stats) const;
|
||||
void clear_extended_stats_list(List* stats_list) const;
|
||||
bool ContainIndexCols(const es_candidate* es, const IndexOptInfo* index) const;
|
||||
ExtendedStats* copy_stats_ptr(ListCell* l) const;
|
||||
void debug_print();
|
||||
double estimate_local_numdistinct(es_bucketsize* bucket, bool left, Path* path);
|
||||
|
|
@ -302,6 +305,7 @@ private:
|
|||
Bitmapset* make_attnums_by_clause_map(es_candidate* es, Bitmapset* attnums, bool left) const;
|
||||
void match_extended_stats(es_candidate* es, List* stats_list, bool left);
|
||||
bool match_pseudo_clauselist(List* clauses, es_candidate* es, List* origin_clause);
|
||||
bool MatchUniqueIndex(const es_candidate* es) const;
|
||||
void modify_distinct_by_possion_model(es_candidate* es, bool left, SpecialJoinInfo* sjinfo) const;
|
||||
char* print_expr(const Node* expr, const List* rtable) const;
|
||||
void print_rel(RangeTblEntry* rel) const;
|
||||
|
|
|
|||
|
|
@ -356,7 +356,8 @@ typedef enum {
|
|||
PARAM_PATH_GEN = 4, /* Parametrized Path Generation */
|
||||
RAND_COST_OPT = 8, /* Optimizing sc_random_page_cost */
|
||||
PARAM_PATH_OPT = 16, /* Parametrized Path Optimization. */
|
||||
PAGE_EST_OPT = 32 /* More accurate (rowstored) index pages estimation */
|
||||
PAGE_EST_OPT = 32, /* More accurate (rowstored) index pages estimation */
|
||||
NO_UNIQUE_INDEX_FIRST = 64 /* use unique index first rule in path generation */
|
||||
} sql_beta_param;
|
||||
|
||||
#define ENABLE_PRED_PUSH(root) \
|
||||
|
|
|
|||
|
|
@ -0,0 +1,36 @@
|
|||
create schema mulcolpk;
|
||||
set current_schema to mulcolpk;
|
||||
create table mulcolpk (a int, b int);
|
||||
insert into mulcolpk values (generate_series(0, 0), generate_series(1, 90));
|
||||
insert into mulcolpk values (generate_series(1, 10), generate_series(0, 0));
|
||||
analyze mulcolpk;
|
||||
--we just test row estimate in index path.
|
||||
set enable_seqscan = off;
|
||||
set enable_bitmapscan = off;
|
||||
set plan_cache_mode = force_generic_plan;
|
||||
--1. create index
|
||||
create index mulcolpk_idx on mulcolpk(a, b);
|
||||
explain select * from mulcolpk where a = 0 and b = 0;
|
||||
QUERY PLAN
|
||||
----------------------------------------------------------------------------------
|
||||
[Bypass]
|
||||
Index Only Scan using mulcolpk_idx on mulcolpk (cost=0.00..8.43 rows=9 width=8)
|
||||
Index Cond: ((a = 0) AND (b = 0))
|
||||
(3 rows)
|
||||
|
||||
--2. create unique index
|
||||
drop index mulcolpk_idx;
|
||||
create unique index mulcolpk_idx on mulcolpk(a, b);
|
||||
explain select * from mulcolpk where a = 0 and b = 0;
|
||||
QUERY PLAN
|
||||
----------------------------------------------------------------------------------
|
||||
[Bypass]
|
||||
Index Only Scan using mulcolpk_idx on mulcolpk (cost=0.00..8.27 rows=1 width=8)
|
||||
Index Cond: ((a = 0) AND (b = 0))
|
||||
(3 rows)
|
||||
|
||||
reset plan_cache_mode;
|
||||
reset enable_bitmapscan;
|
||||
reset enable_seqscan;
|
||||
drop schema mulcolpk cascade;
|
||||
NOTICE: drop cascades to table mulcolpk
|
||||
|
|
@ -0,0 +1,600 @@
|
|||
SET plan_cache_mode = force_generic_plan;
|
||||
-- create range_partition table.
|
||||
CREATE TABLE partition_scan1(a int, b int)
|
||||
PARTITION BY RANGE (a)
|
||||
(
|
||||
PARTITION P1 VALUES LESS THAN(10),
|
||||
PARTITION P2 VALUES LESS THAN(20),
|
||||
PARTITION P3 VALUES LESS THAN(30),
|
||||
PARTITION P4 VALUES LESS THAN(40)
|
||||
);
|
||||
CREATE UNIQUE INDEX index_on_partition_scan1 ON partition_scan1(a) LOCAL;
|
||||
insert into partition_scan1 values(generate_series(1,39,1), generate_series(1,39,1));
|
||||
-- 等于param
|
||||
prepare p1(int) as SELECT * FROM partition_scan1 s1 where s1.a = $1 ORDER BY s1.a;
|
||||
explain (costs off) execute p1(10);
|
||||
QUERY PLAN
|
||||
-----------------------------------------------------------------------------------
|
||||
Partition Iterator
|
||||
Iterations: 4
|
||||
-> Partitioned Index Scan using index_on_partition_scan1 on partition_scan1 s1
|
||||
Index Cond: (a = $1)
|
||||
Selected Partitions: 1..4
|
||||
(5 rows)
|
||||
|
||||
execute p1(10);
|
||||
a | b
|
||||
----+----
|
||||
10 | 10
|
||||
(1 row)
|
||||
|
||||
--大于param
|
||||
prepare p2(int) as SELECT * FROM partition_scan1 s1 where s1.a >$1 ORDER BY s1.a;
|
||||
explain (costs off) execute p2(35);
|
||||
QUERY PLAN
|
||||
--------------------------------------------------------
|
||||
Sort
|
||||
Sort Key: a
|
||||
-> Partition Iterator
|
||||
Iterations: 4
|
||||
-> Partitioned Seq Scan on partition_scan1 s1
|
||||
Filter: (a > $1)
|
||||
Selected Partitions: 1..4
|
||||
(7 rows)
|
||||
|
||||
execute p2(35);
|
||||
a | b
|
||||
----+----
|
||||
36 | 36
|
||||
37 | 37
|
||||
38 | 38
|
||||
39 | 39
|
||||
(4 rows)
|
||||
|
||||
--小于param
|
||||
prepare p3(int) as SELECT * FROM partition_scan1 s1 where s1.a <$1 ORDER BY s1.a;
|
||||
explain (costs off) execute p3(35);
|
||||
QUERY PLAN
|
||||
--------------------------------------------------------
|
||||
Sort
|
||||
Sort Key: a
|
||||
-> Partition Iterator
|
||||
Iterations: 4
|
||||
-> Partitioned Seq Scan on partition_scan1 s1
|
||||
Filter: (a < $1)
|
||||
Selected Partitions: 1..4
|
||||
(7 rows)
|
||||
|
||||
execute p3(35);
|
||||
a | b
|
||||
----+----
|
||||
1 | 1
|
||||
2 | 2
|
||||
3 | 3
|
||||
4 | 4
|
||||
5 | 5
|
||||
6 | 6
|
||||
7 | 7
|
||||
8 | 8
|
||||
9 | 9
|
||||
10 | 10
|
||||
11 | 11
|
||||
12 | 12
|
||||
13 | 13
|
||||
14 | 14
|
||||
15 | 15
|
||||
16 | 16
|
||||
17 | 17
|
||||
18 | 18
|
||||
19 | 19
|
||||
20 | 20
|
||||
21 | 21
|
||||
22 | 22
|
||||
23 | 23
|
||||
24 | 24
|
||||
25 | 25
|
||||
26 | 26
|
||||
27 | 27
|
||||
28 | 28
|
||||
29 | 29
|
||||
30 | 30
|
||||
31 | 31
|
||||
32 | 32
|
||||
33 | 33
|
||||
34 | 34
|
||||
(34 rows)
|
||||
|
||||
-- 大于等于param
|
||||
prepare p4(int) as SELECT * FROM partition_scan1 s1 where s1.a >=$1 ORDER BY s1.a;
|
||||
explain (costs off) execute p4(35);
|
||||
QUERY PLAN
|
||||
--------------------------------------------------------
|
||||
Sort
|
||||
Sort Key: a
|
||||
-> Partition Iterator
|
||||
Iterations: 4
|
||||
-> Partitioned Seq Scan on partition_scan1 s1
|
||||
Filter: (a >= $1)
|
||||
Selected Partitions: 1..4
|
||||
(7 rows)
|
||||
|
||||
execute p4(35);
|
||||
a | b
|
||||
----+----
|
||||
35 | 35
|
||||
36 | 36
|
||||
37 | 37
|
||||
38 | 38
|
||||
39 | 39
|
||||
(5 rows)
|
||||
|
||||
-- 小于等于param
|
||||
prepare p5(int) as SELECT * FROM partition_scan1 s1 where s1.a <=$1 ORDER BY s1.a;
|
||||
explain (costs off) execute p5(35);
|
||||
QUERY PLAN
|
||||
--------------------------------------------------------
|
||||
Sort
|
||||
Sort Key: a
|
||||
-> Partition Iterator
|
||||
Iterations: 4
|
||||
-> Partitioned Seq Scan on partition_scan1 s1
|
||||
Filter: (a <= $1)
|
||||
Selected Partitions: 1..4
|
||||
(7 rows)
|
||||
|
||||
execute p5(35);
|
||||
a | b
|
||||
----+----
|
||||
1 | 1
|
||||
2 | 2
|
||||
3 | 3
|
||||
4 | 4
|
||||
5 | 5
|
||||
6 | 6
|
||||
7 | 7
|
||||
8 | 8
|
||||
9 | 9
|
||||
10 | 10
|
||||
11 | 11
|
||||
12 | 12
|
||||
13 | 13
|
||||
14 | 14
|
||||
15 | 15
|
||||
16 | 16
|
||||
17 | 17
|
||||
18 | 18
|
||||
19 | 19
|
||||
20 | 20
|
||||
21 | 21
|
||||
22 | 22
|
||||
23 | 23
|
||||
24 | 24
|
||||
25 | 25
|
||||
26 | 26
|
||||
27 | 27
|
||||
28 | 28
|
||||
29 | 29
|
||||
30 | 30
|
||||
31 | 31
|
||||
32 | 32
|
||||
33 | 33
|
||||
34 | 34
|
||||
35 | 35
|
||||
(35 rows)
|
||||
|
||||
-- 等于expr
|
||||
prepare p6(int,int) as SELECT * FROM partition_scan1 s1 where s1.a = $1+$2+1 ORDER BY s1.a;
|
||||
explain (costs off) execute p6(10,10);
|
||||
QUERY PLAN
|
||||
-----------------------------------------------------------------------------------
|
||||
Partition Iterator
|
||||
Iterations: 4
|
||||
-> Partitioned Index Scan using index_on_partition_scan1 on partition_scan1 s1
|
||||
Index Cond: (a = (($1 + $2) + 1))
|
||||
Selected Partitions: 1..4
|
||||
(5 rows)
|
||||
|
||||
execute p6(10,10);
|
||||
a | b
|
||||
----+----
|
||||
21 | 21
|
||||
(1 row)
|
||||
|
||||
--大于expr
|
||||
prepare p7(int,int) as SELECT * FROM partition_scan1 s1 where s1.a > $1+$2+1 ORDER BY s1.a;
|
||||
explain (costs off) execute p7(10,10);
|
||||
QUERY PLAN
|
||||
-----------------------------------------------------------------------------
|
||||
Sort
|
||||
Sort Key: a
|
||||
-> Partition Iterator
|
||||
Iterations: 4
|
||||
-> Partitioned Bitmap Heap Scan on partition_scan1 s1
|
||||
Recheck Cond: (a > (($1 + $2) + 1))
|
||||
Selected Partitions: 1..4
|
||||
-> Partitioned Bitmap Index Scan on index_on_partition_scan1
|
||||
Index Cond: (a > (($1 + $2) + 1))
|
||||
Selected Partitions: 1..4
|
||||
(10 rows)
|
||||
|
||||
execute p7(10,10);
|
||||
a | b
|
||||
----+----
|
||||
22 | 22
|
||||
23 | 23
|
||||
24 | 24
|
||||
25 | 25
|
||||
26 | 26
|
||||
27 | 27
|
||||
28 | 28
|
||||
29 | 29
|
||||
30 | 30
|
||||
31 | 31
|
||||
32 | 32
|
||||
33 | 33
|
||||
34 | 34
|
||||
35 | 35
|
||||
36 | 36
|
||||
37 | 37
|
||||
38 | 38
|
||||
39 | 39
|
||||
(18 rows)
|
||||
|
||||
--小于expr
|
||||
prepare p8(int,int) as SELECT * FROM partition_scan1 s1 where s1.a < $1+$2+1 ORDER BY s1.a;
|
||||
explain (costs off) execute p8(10,10);
|
||||
QUERY PLAN
|
||||
-----------------------------------------------------------------------------
|
||||
Sort
|
||||
Sort Key: a
|
||||
-> Partition Iterator
|
||||
Iterations: 4
|
||||
-> Partitioned Bitmap Heap Scan on partition_scan1 s1
|
||||
Recheck Cond: (a < (($1 + $2) + 1))
|
||||
Selected Partitions: 1..4
|
||||
-> Partitioned Bitmap Index Scan on index_on_partition_scan1
|
||||
Index Cond: (a < (($1 + $2) + 1))
|
||||
Selected Partitions: 1..4
|
||||
(10 rows)
|
||||
|
||||
execute p8(10,10);
|
||||
a | b
|
||||
----+----
|
||||
1 | 1
|
||||
2 | 2
|
||||
3 | 3
|
||||
4 | 4
|
||||
5 | 5
|
||||
6 | 6
|
||||
7 | 7
|
||||
8 | 8
|
||||
9 | 9
|
||||
10 | 10
|
||||
11 | 11
|
||||
12 | 12
|
||||
13 | 13
|
||||
14 | 14
|
||||
15 | 15
|
||||
16 | 16
|
||||
17 | 17
|
||||
18 | 18
|
||||
19 | 19
|
||||
20 | 20
|
||||
(20 rows)
|
||||
|
||||
-- 大于等于expr
|
||||
prepare p9(int,int) as SELECT * FROM partition_scan1 s1 where s1.a >= $1+$2+1 ORDER BY s1.a;
|
||||
explain (costs off) execute p9(10,10);
|
||||
QUERY PLAN
|
||||
-----------------------------------------------------------------------------
|
||||
Sort
|
||||
Sort Key: a
|
||||
-> Partition Iterator
|
||||
Iterations: 4
|
||||
-> Partitioned Bitmap Heap Scan on partition_scan1 s1
|
||||
Recheck Cond: (a >= (($1 + $2) + 1))
|
||||
Selected Partitions: 1..4
|
||||
-> Partitioned Bitmap Index Scan on index_on_partition_scan1
|
||||
Index Cond: (a >= (($1 + $2) + 1))
|
||||
Selected Partitions: 1..4
|
||||
(10 rows)
|
||||
|
||||
execute p9(10,10);
|
||||
a | b
|
||||
----+----
|
||||
21 | 21
|
||||
22 | 22
|
||||
23 | 23
|
||||
24 | 24
|
||||
25 | 25
|
||||
26 | 26
|
||||
27 | 27
|
||||
28 | 28
|
||||
29 | 29
|
||||
30 | 30
|
||||
31 | 31
|
||||
32 | 32
|
||||
33 | 33
|
||||
34 | 34
|
||||
35 | 35
|
||||
36 | 36
|
||||
37 | 37
|
||||
38 | 38
|
||||
39 | 39
|
||||
(19 rows)
|
||||
|
||||
-- 小于等于expr
|
||||
prepare p10(int,int) as SELECT * FROM partition_scan1 s1 where s1.a <= $1+$2+1 ORDER BY s1.a;
|
||||
explain (costs off) execute p10(10,10);
|
||||
QUERY PLAN
|
||||
-----------------------------------------------------------------------------
|
||||
Sort
|
||||
Sort Key: a
|
||||
-> Partition Iterator
|
||||
Iterations: 4
|
||||
-> Partitioned Bitmap Heap Scan on partition_scan1 s1
|
||||
Recheck Cond: (a <= (($1 + $2) + 1))
|
||||
Selected Partitions: 1..4
|
||||
-> Partitioned Bitmap Index Scan on index_on_partition_scan1
|
||||
Index Cond: (a <= (($1 + $2) + 1))
|
||||
Selected Partitions: 1..4
|
||||
(10 rows)
|
||||
|
||||
execute p10(10,10);
|
||||
a | b
|
||||
----+----
|
||||
1 | 1
|
||||
2 | 2
|
||||
3 | 3
|
||||
4 | 4
|
||||
5 | 5
|
||||
6 | 6
|
||||
7 | 7
|
||||
8 | 8
|
||||
9 | 9
|
||||
10 | 10
|
||||
11 | 11
|
||||
12 | 12
|
||||
13 | 13
|
||||
14 | 14
|
||||
15 | 15
|
||||
16 | 16
|
||||
17 | 17
|
||||
18 | 18
|
||||
19 | 19
|
||||
20 | 20
|
||||
21 | 21
|
||||
(21 rows)
|
||||
|
||||
--boolexpr_and
|
||||
prepare p11(int,int) as SELECT * FROM partition_scan1 s1 where s1.a >= $1 and s1.b = $2 ORDER BY s1.a;
|
||||
explain (costs off) execute p11(10,10);
|
||||
QUERY PLAN
|
||||
-----------------------------------------------------------------------------
|
||||
Sort
|
||||
Sort Key: a
|
||||
-> Partition Iterator
|
||||
Iterations: 4
|
||||
-> Partitioned Bitmap Heap Scan on partition_scan1 s1
|
||||
Recheck Cond: (a >= $1)
|
||||
Filter: (b = $2)
|
||||
Selected Partitions: 1..4
|
||||
-> Partitioned Bitmap Index Scan on index_on_partition_scan1
|
||||
Index Cond: (a >= $1)
|
||||
Selected Partitions: 1..4
|
||||
(11 rows)
|
||||
|
||||
execute p11(10,10);
|
||||
a | b
|
||||
----+----
|
||||
10 | 10
|
||||
(1 row)
|
||||
|
||||
prepare p12(int,int) as SELECT * FROM partition_scan1 s1 where s1.a > $1 and s1.b < $2;
|
||||
explain (costs off) execute p12(10,10);
|
||||
QUERY PLAN
|
||||
-----------------------------------------------------------------------
|
||||
Partition Iterator
|
||||
Iterations: 4
|
||||
-> Partitioned Bitmap Heap Scan on partition_scan1 s1
|
||||
Recheck Cond: (a > $1)
|
||||
Filter: (b < $2)
|
||||
Selected Partitions: 1..4
|
||||
-> Partitioned Bitmap Index Scan on index_on_partition_scan1
|
||||
Index Cond: (a > $1)
|
||||
Selected Partitions: 1..4
|
||||
(9 rows)
|
||||
|
||||
prepare p13(int,int) as SELECT * FROM partition_scan1 s1 where s1.a <= $1 and s1.b = $2+1;
|
||||
explain (costs off) execute p13(10,10);
|
||||
QUERY PLAN
|
||||
-----------------------------------------------------------------------
|
||||
Partition Iterator
|
||||
Iterations: 4
|
||||
-> Partitioned Bitmap Heap Scan on partition_scan1 s1
|
||||
Recheck Cond: (a <= $1)
|
||||
Filter: (b = ($2 + 1))
|
||||
Selected Partitions: 1..4
|
||||
-> Partitioned Bitmap Index Scan on index_on_partition_scan1
|
||||
Index Cond: (a <= $1)
|
||||
Selected Partitions: 1..4
|
||||
(9 rows)
|
||||
|
||||
prepare p131(int,int) as SELECT * FROM partition_scan1 s1 where s1.a < $1+1 and s1.b > $2+1;
|
||||
explain (costs off) execute p131(10,10);
|
||||
QUERY PLAN
|
||||
-----------------------------------------------------------------------
|
||||
Partition Iterator
|
||||
Iterations: 4
|
||||
-> Partitioned Bitmap Heap Scan on partition_scan1 s1
|
||||
Recheck Cond: (a < ($1 + 1))
|
||||
Filter: (b > ($2 + 1))
|
||||
Selected Partitions: 1..4
|
||||
-> Partitioned Bitmap Index Scan on index_on_partition_scan1
|
||||
Index Cond: (a < ($1 + 1))
|
||||
Selected Partitions: 1..4
|
||||
(9 rows)
|
||||
|
||||
--update
|
||||
prepare p14(int) as UPDATE partition_scan1 set b = b + 10 where a = $1;
|
||||
explain (costs off) execute p14(10);
|
||||
QUERY PLAN
|
||||
--------------------------------------------------------------------------------------
|
||||
Update on partition_scan1
|
||||
-> Partition Iterator
|
||||
Iterations: 4
|
||||
-> Partitioned Index Scan using index_on_partition_scan1 on partition_scan1
|
||||
Index Cond: (a = $1)
|
||||
Selected Partitions: 1..4
|
||||
(6 rows)
|
||||
|
||||
prepare p15(int) as UPDATE partition_scan1 set b = b + 10 where a > $1;
|
||||
explain (costs off) execute p15(10);
|
||||
QUERY PLAN
|
||||
-----------------------------------------------------
|
||||
Update on partition_scan1
|
||||
-> Partition Iterator
|
||||
Iterations: 4
|
||||
-> Partitioned Seq Scan on partition_scan1
|
||||
Filter: (a > $1)
|
||||
Selected Partitions: 1..4
|
||||
(6 rows)
|
||||
|
||||
prepare p16(int) as UPDATE partition_scan1 set b = b + 10 where a >= $1+1;
|
||||
explain (costs off) execute p16(10);
|
||||
QUERY PLAN
|
||||
-----------------------------------------------------------------------------
|
||||
Update on partition_scan1
|
||||
-> Partition Iterator
|
||||
Iterations: 4
|
||||
-> Partitioned Bitmap Heap Scan on partition_scan1
|
||||
Recheck Cond: (a >= ($1 + 1))
|
||||
Selected Partitions: 1..4
|
||||
-> Partitioned Bitmap Index Scan on index_on_partition_scan1
|
||||
Index Cond: (a >= ($1 + 1))
|
||||
Selected Partitions: 1..4
|
||||
(9 rows)
|
||||
|
||||
prepare p17(int) as UPDATE partition_scan1 set b = b + 10 where a <= $1;
|
||||
explain (costs off) execute p17(10);
|
||||
QUERY PLAN
|
||||
-----------------------------------------------------
|
||||
Update on partition_scan1
|
||||
-> Partition Iterator
|
||||
Iterations: 4
|
||||
-> Partitioned Seq Scan on partition_scan1
|
||||
Filter: (a <= $1)
|
||||
Selected Partitions: 1..4
|
||||
(6 rows)
|
||||
|
||||
prepare p18(int) as UPDATE partition_scan1 set b = b + 10 where a < $1;
|
||||
explain (costs off) execute p18(10);
|
||||
QUERY PLAN
|
||||
-----------------------------------------------------
|
||||
Update on partition_scan1
|
||||
-> Partition Iterator
|
||||
Iterations: 4
|
||||
-> Partitioned Seq Scan on partition_scan1
|
||||
Filter: (a < $1)
|
||||
Selected Partitions: 1..4
|
||||
(6 rows)
|
||||
|
||||
prepare p181(int,int) as UPDATE partition_scan1 set b = b + 10 where a < $1 and b < $2;
|
||||
explain (costs off) execute p181(10,10);
|
||||
QUERY PLAN
|
||||
-----------------------------------------------------------------------------
|
||||
Update on partition_scan1
|
||||
-> Partition Iterator
|
||||
Iterations: 4
|
||||
-> Partitioned Bitmap Heap Scan on partition_scan1
|
||||
Recheck Cond: (a < $1)
|
||||
Filter: (b < $2)
|
||||
Selected Partitions: 1..4
|
||||
-> Partitioned Bitmap Index Scan on index_on_partition_scan1
|
||||
Index Cond: (a < $1)
|
||||
Selected Partitions: 1..4
|
||||
(10 rows)
|
||||
|
||||
-- delete
|
||||
prepare p19(int) as DELETE FROM partition_scan1 where a=$1;
|
||||
explain (costs off) execute p19(1);
|
||||
QUERY PLAN
|
||||
--------------------------------------------------------------------------------------
|
||||
Delete on partition_scan1
|
||||
-> Partition Iterator
|
||||
Iterations: 4
|
||||
-> Partitioned Index Scan using index_on_partition_scan1 on partition_scan1
|
||||
Index Cond: (a = $1)
|
||||
Selected Partitions: 1..4
|
||||
(6 rows)
|
||||
|
||||
prepare p20(int) as DELETE FROM partition_scan1 where a>$1;
|
||||
explain (costs off) execute p20(38);
|
||||
QUERY PLAN
|
||||
-----------------------------------------------------
|
||||
Delete on partition_scan1
|
||||
-> Partition Iterator
|
||||
Iterations: 4
|
||||
-> Partitioned Seq Scan on partition_scan1
|
||||
Filter: (a > $1)
|
||||
Selected Partitions: 1..4
|
||||
(6 rows)
|
||||
|
||||
prepare p21(int) as DELETE FROM partition_scan1 where a<$1;
|
||||
explain (costs off) execute p21(3);
|
||||
QUERY PLAN
|
||||
-----------------------------------------------------
|
||||
Delete on partition_scan1
|
||||
-> Partition Iterator
|
||||
Iterations: 4
|
||||
-> Partitioned Seq Scan on partition_scan1
|
||||
Filter: (a < $1)
|
||||
Selected Partitions: 1..4
|
||||
(6 rows)
|
||||
|
||||
prepare p22(int) as DELETE FROM partition_scan1 where a>$1+1;
|
||||
explain (costs off) execute p22(37);
|
||||
QUERY PLAN
|
||||
-----------------------------------------------------------------------------
|
||||
Delete on partition_scan1
|
||||
-> Partition Iterator
|
||||
Iterations: 4
|
||||
-> Partitioned Bitmap Heap Scan on partition_scan1
|
||||
Recheck Cond: (a > ($1 + 1))
|
||||
Selected Partitions: 1..4
|
||||
-> Partitioned Bitmap Index Scan on index_on_partition_scan1
|
||||
Index Cond: (a > ($1 + 1))
|
||||
Selected Partitions: 1..4
|
||||
(9 rows)
|
||||
|
||||
prepare p23(int) as DELETE FROM partition_scan1 where a<$1+1;
|
||||
explain (costs off) execute p23(5);
|
||||
QUERY PLAN
|
||||
-----------------------------------------------------------------------------
|
||||
Delete on partition_scan1
|
||||
-> Partition Iterator
|
||||
Iterations: 4
|
||||
-> Partitioned Bitmap Heap Scan on partition_scan1
|
||||
Recheck Cond: (a < ($1 + 1))
|
||||
Selected Partitions: 1..4
|
||||
-> Partitioned Bitmap Index Scan on index_on_partition_scan1
|
||||
Index Cond: (a < ($1 + 1))
|
||||
Selected Partitions: 1..4
|
||||
(9 rows)
|
||||
|
||||
prepare p24(int,int) as DELETE FROM partition_scan1 where a>$1 and b>$2;
|
||||
explain (costs off) execute p24(30,1);
|
||||
QUERY PLAN
|
||||
-----------------------------------------------------------------------------
|
||||
Delete on partition_scan1
|
||||
-> Partition Iterator
|
||||
Iterations: 4
|
||||
-> Partitioned Bitmap Heap Scan on partition_scan1
|
||||
Recheck Cond: (a > $1)
|
||||
Filter: (b > $2)
|
||||
Selected Partitions: 1..4
|
||||
-> Partitioned Bitmap Index Scan on index_on_partition_scan1
|
||||
Index Cond: (a > $1)
|
||||
Selected Partitions: 1..4
|
||||
(10 rows)
|
||||
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
create schema unique_index_first;
|
||||
set current_schema to unique_index_first;
|
||||
create table unique_index_first (col1 int, col2 int, col3 int, col4 int, col5 int);
|
||||
alter table unique_index_first add primary key (col1, col2, col3, col4);
|
||||
NOTICE: ALTER TABLE / ADD PRIMARY KEY will create implicit index "unique_index_first_pkey" for table "unique_index_first"
|
||||
create index index_no_unique on unique_index_first using btree(col1, col2, col3, col5);
|
||||
--1. A btree plan containing unique columns is prefered.
|
||||
explain (costs off) select * from unique_index_first where col2 = 2 and col4 = 4 and col3 = 3 and col1 = 1;
|
||||
QUERY PLAN
|
||||
-------------------------------------------------------------------------
|
||||
[Bypass]
|
||||
Index Scan using unique_index_first_pkey on unique_index_first
|
||||
Index Cond: ((col1 = 1) AND (col2 = 2) AND (col3 = 3) AND (col4 = 4))
|
||||
(3 rows)
|
||||
|
||||
--2. Only equivalence constraint can active the unique_btree_index rule.
|
||||
explain (costs off) select * from unique_index_first where col2 = 2 and col4 < 4 and col3 = 3 and col1 = 1;
|
||||
QUERY PLAN
|
||||
----------------------------------------------------------
|
||||
Index Scan using index_no_unique on unique_index_first
|
||||
Index Cond: ((col1 = 1) AND (col2 = 2) AND (col3 = 3))
|
||||
Filter: (col4 < 4)
|
||||
(3 rows)
|
||||
|
||||
--3. test seqscan
|
||||
set enable_indexscan=off;
|
||||
set enable_bitmapscan=off;
|
||||
explain (costs off) select * from unique_index_first where col2 = 2 and col4 = 4 and col3 = 3 and col1 = 1;
|
||||
QUERY PLAN
|
||||
---------------------------------------------------------------------
|
||||
Seq Scan on unique_index_first
|
||||
Filter: ((col2 = 2) AND (col4 = 4) AND (col3 = 3) AND (col1 = 1))
|
||||
(2 rows)
|
||||
|
||||
explain (costs off) select * from unique_index_first where col2 = 2 and col4 < 4 and col3 = 3 and col1 = 1;
|
||||
QUERY PLAN
|
||||
---------------------------------------------------------------------
|
||||
Seq Scan on unique_index_first
|
||||
Filter: ((col4 < 4) AND (col2 = 2) AND (col3 = 3) AND (col1 = 1))
|
||||
(2 rows)
|
||||
|
||||
reset sql_beta_feature;
|
||||
drop schema unique_index_first cascade;
|
||||
NOTICE: drop cascades to table unique_index_first
|
||||
|
|
@ -169,13 +169,14 @@ EXPLAIN (VERBOSE TRUE, COSTS FALSE)DELETE FROM DELETE_XC_C WHERE C2 IN (SELECT D
|
|||
(8 rows)
|
||||
|
||||
EXPLAIN (VERBOSE TRUE, COSTS FALSE)DELETE FROM DELETE_XC_C WHERE C3 = 1 AND C1 = 5;
|
||||
QUERY PLAN
|
||||
-----------------------------------------------------------------
|
||||
QUERY PLAN
|
||||
---------------------------------------------------------------------
|
||||
[Bypass]
|
||||
Delete on public.delete_xc_c
|
||||
-> Seq Scan on public.delete_xc_c
|
||||
-> Index Scan using con_delete on public.delete_xc_c
|
||||
Output: ctid
|
||||
Filter: ((delete_xc_c.c3 = 1) AND (delete_xc_c.c1 = 5))
|
||||
(4 rows)
|
||||
Index Cond: ((delete_xc_c.c3 = 1) AND (delete_xc_c.c1 = 5))
|
||||
(5 rows)
|
||||
|
||||
EXPLAIN (VERBOSE TRUE, COSTS FALSE)DELETE FROM DELETE_XC_C WHERE C3 = 0;
|
||||
QUERY PLAN
|
||||
|
|
@ -231,13 +232,14 @@ EXPLAIN (VERBOSE TRUE, COSTS FALSE)DELETE FROM DELETE_XC_C WHERE C2 IN (SELECT D
|
|||
(8 rows)
|
||||
|
||||
EXPLAIN (VERBOSE TRUE, COSTS FALSE)DELETE FROM DELETE_XC_C WHERE C3 = 1 AND C1 = 5;
|
||||
QUERY PLAN
|
||||
-----------------------------------------------------------------
|
||||
QUERY PLAN
|
||||
---------------------------------------------------------------------
|
||||
[Bypass]
|
||||
Delete on public.delete_xc_c
|
||||
-> Seq Scan on public.delete_xc_c
|
||||
-> Index Scan using con_delete on public.delete_xc_c
|
||||
Output: ctid
|
||||
Filter: ((delete_xc_c.c3 = 1) AND (delete_xc_c.c1 = 5))
|
||||
(4 rows)
|
||||
Index Cond: ((delete_xc_c.c3 = 1) AND (delete_xc_c.c1 = 5))
|
||||
(5 rows)
|
||||
|
||||
EXPLAIN (VERBOSE TRUE, COSTS FALSE)DELETE FROM DELETE_XC_C WHERE C3 = 0;
|
||||
QUERY PLAN
|
||||
|
|
@ -293,13 +295,14 @@ EXPLAIN (VERBOSE TRUE, COSTS FALSE)DELETE FROM DELETE_XC_C WHERE C2 IN (SELECT D
|
|||
(8 rows)
|
||||
|
||||
EXPLAIN (VERBOSE TRUE, COSTS FALSE)DELETE FROM DELETE_XC_C WHERE C3 = 1 AND C1 = 5;
|
||||
QUERY PLAN
|
||||
-----------------------------------------------------------------
|
||||
QUERY PLAN
|
||||
---------------------------------------------------------------------
|
||||
[Bypass]
|
||||
Delete on public.delete_xc_c
|
||||
-> Seq Scan on public.delete_xc_c
|
||||
-> Index Scan using con_delete on public.delete_xc_c
|
||||
Output: ctid
|
||||
Filter: ((delete_xc_c.c3 = 1) AND (delete_xc_c.c1 = 5))
|
||||
(4 rows)
|
||||
Index Cond: ((delete_xc_c.c3 = 1) AND (delete_xc_c.c1 = 5))
|
||||
(5 rows)
|
||||
|
||||
EXPLAIN (VERBOSE TRUE, COSTS FALSE)DELETE FROM DELETE_XC_C WHERE C3 = 0;
|
||||
QUERY PLAN
|
||||
|
|
@ -532,12 +535,12 @@ EXPLAIN (VERBOSE TRUE, COSTS FALSE)DELETE FROM DELETE_XC_C WHERE C2 IN (SELECT D
|
|||
(8 rows)
|
||||
|
||||
EXPLAIN (VERBOSE TRUE, COSTS FALSE)DELETE FROM DELETE_XC_C WHERE C3 = 1 AND C1 = 5;
|
||||
QUERY PLAN
|
||||
-----------------------------------------------------------------
|
||||
QUERY PLAN
|
||||
---------------------------------------------------------------------
|
||||
Delete on public.delete_xc_c
|
||||
-> Seq Scan on public.delete_xc_c
|
||||
-> Index Scan using con_delete on public.delete_xc_c
|
||||
Output: ctid
|
||||
Filter: ((delete_xc_c.c3 = 1) AND (delete_xc_c.c1 = 5))
|
||||
Index Cond: ((delete_xc_c.c3 = 1) AND (delete_xc_c.c1 = 5))
|
||||
(4 rows)
|
||||
|
||||
EXPLAIN (VERBOSE TRUE, COSTS FALSE)DELETE FROM DELETE_XC_C WHERE C3 = 0;
|
||||
|
|
@ -845,12 +848,12 @@ EXPLAIN (VERBOSE TRUE, COSTS FALSE)DELETE FROM DELETE_XC_C WHERE C2 IN (SELECT D
|
|||
(8 rows)
|
||||
|
||||
EXPLAIN (VERBOSE TRUE, COSTS FALSE)DELETE FROM DELETE_XC_C WHERE C3 = 1 AND C1 = 5;
|
||||
QUERY PLAN
|
||||
-----------------------------------------------------------------
|
||||
QUERY PLAN
|
||||
---------------------------------------------------------------------
|
||||
Delete on public.delete_xc_c
|
||||
-> Seq Scan on public.delete_xc_c
|
||||
-> Index Scan using con_delete on public.delete_xc_c
|
||||
Output: ctid
|
||||
Filter: ((delete_xc_c.c3 = 1) AND (delete_xc_c.c1 = 5))
|
||||
Index Cond: ((delete_xc_c.c3 = 1) AND (delete_xc_c.c1 = 5))
|
||||
(4 rows)
|
||||
|
||||
EXPLAIN (VERBOSE TRUE, COSTS FALSE)DELETE FROM DELETE_XC_C WHERE C3 = 0;
|
||||
|
|
@ -914,13 +917,14 @@ EXPLAIN (VERBOSE TRUE, COSTS FALSE) UPDATE UPDATE_XC_C SET (C2) = (SELECT D3 FRO
|
|||
(7 rows)
|
||||
|
||||
EXPLAIN (VERBOSE TRUE, COSTS FALSE) UPDATE UPDATE_XC_C SET C2 = 0 WHERE C3 = 1 AND C1 = 5;
|
||||
QUERY PLAN
|
||||
-----------------------------------------------------------------
|
||||
QUERY PLAN
|
||||
---------------------------------------------------------------------
|
||||
[Bypass]
|
||||
Update on public.update_xc_c
|
||||
-> Seq Scan on public.update_xc_c
|
||||
-> Index Scan using con_update on public.update_xc_c
|
||||
Output: c1, 0, c3, ctid
|
||||
Filter: ((update_xc_c.c3 = 1) AND (update_xc_c.c1 = 5))
|
||||
(4 rows)
|
||||
Index Cond: ((update_xc_c.c3 = 1) AND (update_xc_c.c1 = 5))
|
||||
(5 rows)
|
||||
|
||||
EXPLAIN (VERBOSE TRUE, COSTS FALSE) UPDATE UPDATE_XC_C SET C2 = 1 WHERE C3 = 0;
|
||||
QUERY PLAN
|
||||
|
|
@ -962,13 +966,14 @@ EXPLAIN (VERBOSE TRUE, COSTS FALSE) UPDATE UPDATE_XC_C SET (C2) = (SELECT D3 FRO
|
|||
(7 rows)
|
||||
|
||||
EXPLAIN (VERBOSE TRUE, COSTS FALSE) UPDATE UPDATE_XC_C SET C2 = 0 WHERE C3 = 1 AND C1 = 5;
|
||||
QUERY PLAN
|
||||
-----------------------------------------------------------------
|
||||
QUERY PLAN
|
||||
---------------------------------------------------------------------
|
||||
[Bypass]
|
||||
Update on public.update_xc_c
|
||||
-> Seq Scan on public.update_xc_c
|
||||
-> Index Scan using con_update on public.update_xc_c
|
||||
Output: c1, 0, c3, ctid
|
||||
Filter: ((update_xc_c.c3 = 1) AND (update_xc_c.c1 = 5))
|
||||
(4 rows)
|
||||
Index Cond: ((update_xc_c.c3 = 1) AND (update_xc_c.c1 = 5))
|
||||
(5 rows)
|
||||
|
||||
EXPLAIN (VERBOSE TRUE, COSTS FALSE) UPDATE UPDATE_XC_C SET C2 = 1 WHERE C3 = 0;
|
||||
QUERY PLAN
|
||||
|
|
@ -1010,13 +1015,14 @@ EXPLAIN (VERBOSE TRUE, COSTS FALSE) UPDATE UPDATE_XC_C SET (C2) = (SELECT D3 FRO
|
|||
(7 rows)
|
||||
|
||||
EXPLAIN (VERBOSE TRUE, COSTS FALSE) UPDATE UPDATE_XC_C SET C2 = 0 WHERE C3 = 1 AND C1 = 5;
|
||||
QUERY PLAN
|
||||
-----------------------------------------------------------------
|
||||
QUERY PLAN
|
||||
---------------------------------------------------------------------
|
||||
[Bypass]
|
||||
Update on public.update_xc_c
|
||||
-> Seq Scan on public.update_xc_c
|
||||
-> Index Scan using con_update on public.update_xc_c
|
||||
Output: c1, 0, c3, ctid
|
||||
Filter: ((update_xc_c.c3 = 1) AND (update_xc_c.c1 = 5))
|
||||
(4 rows)
|
||||
Index Cond: ((update_xc_c.c3 = 1) AND (update_xc_c.c1 = 5))
|
||||
(5 rows)
|
||||
|
||||
EXPLAIN (VERBOSE TRUE, COSTS FALSE) UPDATE UPDATE_XC_C SET C2 = 1 WHERE C3 = 0;
|
||||
QUERY PLAN
|
||||
|
|
@ -1291,12 +1297,12 @@ EXPLAIN (VERBOSE TRUE, COSTS FALSE) UPDATE UPDATE_XC_C SET (C2) = (SELECT D3 FRO
|
|||
(7 rows)
|
||||
|
||||
EXPLAIN (VERBOSE TRUE, COSTS FALSE) UPDATE UPDATE_XC_C SET C2 = 0 WHERE C3 = 1 AND C1 = 5;
|
||||
QUERY PLAN
|
||||
-----------------------------------------------------------------
|
||||
QUERY PLAN
|
||||
---------------------------------------------------------------------
|
||||
Update on public.update_xc_c
|
||||
-> Seq Scan on public.update_xc_c
|
||||
-> Index Scan using con_update on public.update_xc_c
|
||||
Output: c1, 0, c3, ctid
|
||||
Filter: ((update_xc_c.c3 = 1) AND (update_xc_c.c1 = 5))
|
||||
Index Cond: ((update_xc_c.c3 = 1) AND (update_xc_c.c1 = 5))
|
||||
(4 rows)
|
||||
|
||||
EXPLAIN (VERBOSE TRUE, COSTS FALSE) UPDATE UPDATE_XC_C SET C2 = 1 WHERE C3 = 0;
|
||||
|
|
@ -1349,12 +1355,12 @@ EXPLAIN (VERBOSE TRUE, COSTS FALSE) UPDATE UPDATE_XC_C SET (C2) = (SELECT D3 FRO
|
|||
(7 rows)
|
||||
|
||||
EXPLAIN (VERBOSE TRUE, COSTS FALSE) UPDATE UPDATE_XC_C SET C2 = 0 WHERE C3 = 1 AND C1 = 5;
|
||||
QUERY PLAN
|
||||
-----------------------------------------------------------------
|
||||
QUERY PLAN
|
||||
---------------------------------------------------------------------
|
||||
Update on public.update_xc_c
|
||||
-> Seq Scan on public.update_xc_c
|
||||
-> Index Scan using con_update on public.update_xc_c
|
||||
Output: c1, 0, c3, ctid
|
||||
Filter: ((update_xc_c.c3 = 1) AND (update_xc_c.c1 = 5))
|
||||
Index Cond: ((update_xc_c.c3 = 1) AND (update_xc_c.c1 = 5))
|
||||
(4 rows)
|
||||
|
||||
EXPLAIN (VERBOSE TRUE, COSTS FALSE) UPDATE UPDATE_XC_C SET C2 = 1 WHERE C3 = 0;
|
||||
|
|
@ -1630,12 +1636,12 @@ EXPLAIN (VERBOSE TRUE, COSTS FALSE) UPDATE UPDATE_XC_C SET (C2) = (SELECT D3 FRO
|
|||
(7 rows)
|
||||
|
||||
EXPLAIN (VERBOSE TRUE, COSTS FALSE) UPDATE UPDATE_XC_C SET C2 = 0 WHERE C3 = 1 AND C1 = 5;
|
||||
QUERY PLAN
|
||||
-----------------------------------------------------------------
|
||||
QUERY PLAN
|
||||
---------------------------------------------------------------------
|
||||
Update on public.update_xc_c
|
||||
-> Seq Scan on public.update_xc_c
|
||||
-> Index Scan using con_update on public.update_xc_c
|
||||
Output: c1, 0, c3, ctid
|
||||
Filter: ((update_xc_c.c3 = 1) AND (update_xc_c.c1 = 5))
|
||||
Index Cond: ((update_xc_c.c3 = 1) AND (update_xc_c.c1 = 5))
|
||||
(4 rows)
|
||||
|
||||
EXPLAIN (VERBOSE TRUE, COSTS FALSE) UPDATE UPDATE_XC_C SET C2 = 1 WHERE C3 = 0;
|
||||
|
|
|
|||
|
|
@ -760,3 +760,6 @@ test: leaky_function_operator
|
|||
#test: gs_guc
|
||||
|
||||
test: smp
|
||||
test: mulcolpk
|
||||
test: pbe_partition
|
||||
test: unique_index_first
|
||||
|
|
|
|||
|
|
@ -0,0 +1,26 @@
|
|||
create schema mulcolpk;
|
||||
set current_schema to mulcolpk;
|
||||
create table mulcolpk (a int, b int);
|
||||
insert into mulcolpk values (generate_series(0, 0), generate_series(1, 90));
|
||||
insert into mulcolpk values (generate_series(1, 10), generate_series(0, 0));
|
||||
analyze mulcolpk;
|
||||
|
||||
--we just test row estimate in index path.
|
||||
set enable_seqscan = off;
|
||||
set enable_bitmapscan = off;
|
||||
set plan_cache_mode = force_generic_plan;
|
||||
|
||||
--1. create index
|
||||
create index mulcolpk_idx on mulcolpk(a, b);
|
||||
explain select * from mulcolpk where a = 0 and b = 0;
|
||||
|
||||
--2. create unique index
|
||||
drop index mulcolpk_idx;
|
||||
create unique index mulcolpk_idx on mulcolpk(a, b);
|
||||
explain select * from mulcolpk where a = 0 and b = 0;
|
||||
|
||||
reset plan_cache_mode;
|
||||
reset enable_bitmapscan;
|
||||
reset enable_seqscan;
|
||||
|
||||
drop schema mulcolpk cascade;
|
||||
|
|
@ -0,0 +1,123 @@
|
|||
SET plan_cache_mode = force_generic_plan;
|
||||
|
||||
|
||||
-- create range_partition table.
|
||||
|
||||
CREATE TABLE partition_scan1(a int, b int)
|
||||
PARTITION BY RANGE (a)
|
||||
(
|
||||
PARTITION P1 VALUES LESS THAN(10),
|
||||
PARTITION P2 VALUES LESS THAN(20),
|
||||
PARTITION P3 VALUES LESS THAN(30),
|
||||
PARTITION P4 VALUES LESS THAN(40)
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX index_on_partition_scan1 ON partition_scan1(a) LOCAL;
|
||||
|
||||
insert into partition_scan1 values(generate_series(1,39,1), generate_series(1,39,1));
|
||||
|
||||
-- 等于param
|
||||
prepare p1(int) as SELECT * FROM partition_scan1 s1 where s1.a = $1 ORDER BY s1.a;
|
||||
explain (costs off) execute p1(10);
|
||||
execute p1(10);
|
||||
|
||||
--大于param
|
||||
prepare p2(int) as SELECT * FROM partition_scan1 s1 where s1.a >$1 ORDER BY s1.a;
|
||||
explain (costs off) execute p2(35);
|
||||
execute p2(35);
|
||||
|
||||
--小于param
|
||||
prepare p3(int) as SELECT * FROM partition_scan1 s1 where s1.a <$1 ORDER BY s1.a;
|
||||
explain (costs off) execute p3(35);
|
||||
execute p3(35);
|
||||
|
||||
-- 大于等于param
|
||||
prepare p4(int) as SELECT * FROM partition_scan1 s1 where s1.a >=$1 ORDER BY s1.a;
|
||||
explain (costs off) execute p4(35);
|
||||
execute p4(35);
|
||||
|
||||
-- 小于等于param
|
||||
prepare p5(int) as SELECT * FROM partition_scan1 s1 where s1.a <=$1 ORDER BY s1.a;
|
||||
explain (costs off) execute p5(35);
|
||||
execute p5(35);
|
||||
|
||||
|
||||
-- 等于expr
|
||||
prepare p6(int,int) as SELECT * FROM partition_scan1 s1 where s1.a = $1+$2+1 ORDER BY s1.a;
|
||||
explain (costs off) execute p6(10,10);
|
||||
execute p6(10,10);
|
||||
|
||||
--大于expr
|
||||
prepare p7(int,int) as SELECT * FROM partition_scan1 s1 where s1.a > $1+$2+1 ORDER BY s1.a;
|
||||
explain (costs off) execute p7(10,10);
|
||||
execute p7(10,10);
|
||||
|
||||
--小于expr
|
||||
prepare p8(int,int) as SELECT * FROM partition_scan1 s1 where s1.a < $1+$2+1 ORDER BY s1.a;
|
||||
explain (costs off) execute p8(10,10);
|
||||
execute p8(10,10);
|
||||
|
||||
-- 大于等于expr
|
||||
prepare p9(int,int) as SELECT * FROM partition_scan1 s1 where s1.a >= $1+$2+1 ORDER BY s1.a;
|
||||
explain (costs off) execute p9(10,10);
|
||||
execute p9(10,10);
|
||||
|
||||
-- 小于等于expr
|
||||
prepare p10(int,int) as SELECT * FROM partition_scan1 s1 where s1.a <= $1+$2+1 ORDER BY s1.a;
|
||||
explain (costs off) execute p10(10,10);
|
||||
execute p10(10,10);
|
||||
|
||||
--boolexpr_and
|
||||
prepare p11(int,int) as SELECT * FROM partition_scan1 s1 where s1.a >= $1 and s1.b = $2 ORDER BY s1.a;
|
||||
explain (costs off) execute p11(10,10);
|
||||
execute p11(10,10);
|
||||
|
||||
prepare p12(int,int) as SELECT * FROM partition_scan1 s1 where s1.a > $1 and s1.b < $2;
|
||||
explain (costs off) execute p12(10,10);
|
||||
|
||||
prepare p13(int,int) as SELECT * FROM partition_scan1 s1 where s1.a <= $1 and s1.b = $2+1;
|
||||
explain (costs off) execute p13(10,10);
|
||||
|
||||
prepare p131(int,int) as SELECT * FROM partition_scan1 s1 where s1.a < $1+1 and s1.b > $2+1;
|
||||
explain (costs off) execute p131(10,10);
|
||||
|
||||
|
||||
--update
|
||||
prepare p14(int) as UPDATE partition_scan1 set b = b + 10 where a = $1;
|
||||
explain (costs off) execute p14(10);
|
||||
|
||||
prepare p15(int) as UPDATE partition_scan1 set b = b + 10 where a > $1;
|
||||
explain (costs off) execute p15(10);
|
||||
|
||||
prepare p16(int) as UPDATE partition_scan1 set b = b + 10 where a >= $1+1;
|
||||
explain (costs off) execute p16(10);
|
||||
|
||||
prepare p17(int) as UPDATE partition_scan1 set b = b + 10 where a <= $1;
|
||||
explain (costs off) execute p17(10);
|
||||
|
||||
prepare p18(int) as UPDATE partition_scan1 set b = b + 10 where a < $1;
|
||||
explain (costs off) execute p18(10);
|
||||
|
||||
prepare p181(int,int) as UPDATE partition_scan1 set b = b + 10 where a < $1 and b < $2;
|
||||
explain (costs off) execute p181(10,10);
|
||||
|
||||
|
||||
|
||||
-- delete
|
||||
prepare p19(int) as DELETE FROM partition_scan1 where a=$1;
|
||||
explain (costs off) execute p19(1);
|
||||
|
||||
prepare p20(int) as DELETE FROM partition_scan1 where a>$1;
|
||||
explain (costs off) execute p20(38);
|
||||
|
||||
prepare p21(int) as DELETE FROM partition_scan1 where a<$1;
|
||||
explain (costs off) execute p21(3);
|
||||
|
||||
prepare p22(int) as DELETE FROM partition_scan1 where a>$1+1;
|
||||
explain (costs off) execute p22(37);
|
||||
|
||||
prepare p23(int) as DELETE FROM partition_scan1 where a<$1+1;
|
||||
explain (costs off) execute p23(5);
|
||||
|
||||
prepare p24(int,int) as DELETE FROM partition_scan1 where a>$1 and b>$2;
|
||||
explain (costs off) execute p24(30,1);
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
create schema unique_index_first;
|
||||
set current_schema to unique_index_first;
|
||||
|
||||
create table unique_index_first (col1 int, col2 int, col3 int, col4 int, col5 int);
|
||||
alter table unique_index_first add primary key (col1, col2, col3, col4);
|
||||
create index index_no_unique on unique_index_first using btree(col1, col2, col3, col5);
|
||||
|
||||
--1. A btree plan containing unique columns is prefered.
|
||||
explain (costs off) select * from unique_index_first where col2 = 2 and col4 = 4 and col3 = 3 and col1 = 1;
|
||||
|
||||
--2. Only equivalence constraint can active the unique_btree_index rule.
|
||||
explain (costs off) select * from unique_index_first where col2 = 2 and col4 < 4 and col3 = 3 and col1 = 1;
|
||||
|
||||
--3. test seqscan
|
||||
set enable_indexscan=off;
|
||||
set enable_bitmapscan=off;
|
||||
|
||||
explain (costs off) select * from unique_index_first where col2 = 2 and col4 = 4 and col3 = 3 and col1 = 1;
|
||||
explain (costs off) select * from unique_index_first where col2 = 2 and col4 < 4 and col3 = 3 and col1 = 1;
|
||||
|
||||
reset sql_beta_feature;
|
||||
drop schema unique_index_first cascade;
|
||||
Loading…
Reference in New Issue