!993 Fix issue: Fix a bug on the index advisor: bad type casting and strengthen the hypo-index
Merge pull request !993 from liuly/master
This commit is contained in:
@ -91,7 +91,8 @@ static void hypo_set_indexname(hypoIndex *entry, const char *indexname);
|
|||||||
static void hypo_index_reset(void);
|
static void hypo_index_reset(void);
|
||||||
static void hypo_injectHypotheticalIndex(PlannerInfo *root, Oid relationObjectId, bool inhparent, RelOptInfo *rel,
|
static void hypo_injectHypotheticalIndex(PlannerInfo *root, Oid relationObjectId, bool inhparent, RelOptInfo *rel,
|
||||||
Relation relation, hypoIndex *entry);
|
Relation relation, hypoIndex *entry);
|
||||||
|
static List *get_table_indexes(Oid oid);
|
||||||
|
static List *get_index_attrnum(Oid oid);
|
||||||
|
|
||||||
void InitHypopg()
|
void InitHypopg()
|
||||||
{
|
{
|
||||||
@ -217,6 +218,31 @@ static void hypo_executorEnd_hook(QueryDesc *queryDesc)
|
|||||||
standard_ExecutorEnd(queryDesc);
|
standard_ExecutorEnd(queryDesc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
List *get_table_indexes(Oid oid)
|
||||||
|
{
|
||||||
|
Relation rel = heap_open(oid, NoLock);
|
||||||
|
List *indexes = RelationGetIndexList(rel);
|
||||||
|
heap_close(rel, NoLock);
|
||||||
|
return indexes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return the names of all the columns involved in the index. */
|
||||||
|
List *get_index_attrnum(Oid index_oid)
|
||||||
|
{
|
||||||
|
HeapTuple index_tup = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(index_oid));
|
||||||
|
if (!HeapTupleIsValid(index_tup))
|
||||||
|
ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("cache lookup failed for index %u", index_oid)));
|
||||||
|
Form_pg_index index_form = (Form_pg_index)GETSTRUCT(index_tup);
|
||||||
|
int2vector *attnums = &(index_form->indkey);
|
||||||
|
// get attrnum from table oid.
|
||||||
|
List *attrnum = NIL;
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < attnums->dim1; i++) {
|
||||||
|
attrnum = lappend_int(attrnum, attnums->values[i]);
|
||||||
|
}
|
||||||
|
ReleaseSysCache(index_tup);
|
||||||
|
return attrnum;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This function will execute the "hypo_injectHypotheticalIndex" for every
|
* This function will execute the "hypo_injectHypotheticalIndex" for every
|
||||||
@ -243,7 +269,32 @@ static void hypo_get_relation_info_hook(PlannerInfo *root, Oid relationObjectId,
|
|||||||
* hypothetical index found, add it to the relation's
|
* hypothetical index found, add it to the relation's
|
||||||
* indextlist
|
* indextlist
|
||||||
*/
|
*/
|
||||||
hypo_injectHypotheticalIndex(root, relationObjectId, inhparent, rel, relation, entry);
|
List *indexes = get_table_indexes(entry->relid);
|
||||||
|
ListCell *index = NULL;
|
||||||
|
bool match_flag = false;
|
||||||
|
foreach (index, indexes) {
|
||||||
|
List *attrnums = get_index_attrnum(lfirst_oid(index));
|
||||||
|
if (attrnums == NIL) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (entry->ncolumns > attrnums->length) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
match_flag = true;
|
||||||
|
for (int i = 0; i < entry->ncolumns; i++) {
|
||||||
|
if (entry->indexkeys[i] != list_nth_int(attrnums, i)) {
|
||||||
|
match_flag = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// the suggested index has existed
|
||||||
|
if (match_flag) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!match_flag) {
|
||||||
|
hypo_injectHypotheticalIndex(root, relationObjectId, inhparent, rel, relation, entry);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -906,6 +906,11 @@ void parse_join_expr(JoinExpr *join_tree)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (nodeTag(join_tree->larg) != T_RangeVar ||
|
||||||
|
nodeTag(join_tree->rarg) != T_RangeVar) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
List *join_fields = join_tree->usingClause;
|
List *join_fields = join_tree->usingClause;
|
||||||
char *l_table_name = ((RangeVar *)(join_tree->larg))->relname;
|
char *l_table_name = ((RangeVar *)(join_tree->larg))->relname;
|
||||||
char *r_table_name = ((RangeVar *)(join_tree->rarg))->relname;
|
char *r_table_name = ((RangeVar *)(join_tree->rarg))->relname;
|
||||||
@ -1548,7 +1553,7 @@ void add_index_from_group_order(TableCell *table, List *clause, List *target_lis
|
|||||||
ListCell *prev = NULL;
|
ListCell *prev = NULL;
|
||||||
foreach (cur, table->index) {
|
foreach (cur, table->index) {
|
||||||
IndexCell *table_index = (IndexCell *)lfirst(cur);
|
IndexCell *table_index = (IndexCell *)lfirst(cur);
|
||||||
if (strcasecmp(table_index->index_name, index->index_name) == 0) {
|
if (index->index_name == NULL || strcasecmp(table_index->index_name, index->index_name) == 0) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (table_index->op && strcasecmp(table_index->op, "=") != 0) {
|
if (table_index->op && strcasecmp(table_index->op, "=") != 0) {
|
||||||
|
@ -7,6 +7,8 @@ SQL_TYPE = ['select', 'delete', 'insert', 'update']
|
|||||||
|
|
||||||
|
|
||||||
def output_valid_sql(sql):
|
def output_valid_sql(sql):
|
||||||
|
if 'from pg_' in sql.lower():
|
||||||
|
return ''
|
||||||
if any(tp in sql.lower() for tp in SQL_TYPE[1:]):
|
if any(tp in sql.lower() for tp in SQL_TYPE[1:]):
|
||||||
return sql if sql.endswith('; ') else sql + ';'
|
return sql if sql.endswith('; ') else sql + ';'
|
||||||
elif SQL_TYPE[0] in sql.lower() and 'from ' in sql.lower():
|
elif SQL_TYPE[0] in sql.lower() and 'from ' in sql.lower():
|
||||||
@ -17,53 +19,59 @@ def output_valid_sql(sql):
|
|||||||
def extract_sql_from_log(log_path):
|
def extract_sql_from_log(log_path):
|
||||||
files = os.listdir(log_path)
|
files = os.listdir(log_path)
|
||||||
for file in files:
|
for file in files:
|
||||||
if not os.path.isdir(file) and '.swap' not in file:
|
file_path = log_path + "/" + file
|
||||||
with open(log_path + "/" + file, mode='r') as f:
|
if os.path.isfile(file_path) and re.search(r'.log$', file):
|
||||||
|
with open(file_path, mode='r') as f:
|
||||||
line = f.readline()
|
line = f.readline()
|
||||||
sql = ''
|
sql = ''
|
||||||
statement_flag = False
|
statement_flag = False
|
||||||
execute_flag = False
|
execute_flag = False
|
||||||
|
|
||||||
while line:
|
while line:
|
||||||
# Identify statement scene
|
try:
|
||||||
if re.search('statement: ', line, re.IGNORECASE):
|
# Identify statement scene
|
||||||
statement_flag = True
|
if re.search('statement: ', line, re.IGNORECASE):
|
||||||
if output_valid_sql(sql):
|
statement_flag = True
|
||||||
yield output_valid_sql(sql)
|
if output_valid_sql(sql):
|
||||||
sql = re.search(r'statement: (.*)', line.strip(),
|
yield output_valid_sql(sql)
|
||||||
re.IGNORECASE).group(1) + ' '
|
sql = re.search(r'statement: (.*)', line.strip(),
|
||||||
line = f.readline()
|
re.IGNORECASE).group(1) + ' '
|
||||||
|
line = f.readline()
|
||||||
|
|
||||||
# Identify execute statement scene
|
# Identify execute statement scene
|
||||||
elif re.search(r'execute .*:', line, re.IGNORECASE):
|
elif re.search(r'execute .*:', line, re.IGNORECASE):
|
||||||
if output_valid_sql(sql):
|
if output_valid_sql(sql):
|
||||||
yield output_valid_sql(sql)
|
yield output_valid_sql(sql)
|
||||||
execute_flag = True
|
execute_flag = True
|
||||||
sql = re.search(r'execute .*: (.*)', line.strip(), re.IGNORECASE).group(1)
|
sql = re.search(r'execute .*: (.*)', line.strip(), re.IGNORECASE).group(1)
|
||||||
line = f.readline()
|
line = f.readline()
|
||||||
else:
|
else:
|
||||||
if statement_flag:
|
if statement_flag:
|
||||||
if re.match(r'^\t', line):
|
if re.match(r'^\t', line):
|
||||||
sql += line.strip('\t\n')
|
sql += line.strip('\t\n')
|
||||||
else:
|
|
||||||
statement_flag = False
|
|
||||||
if output_valid_sql(sql):
|
|
||||||
yield output_valid_sql(sql)
|
|
||||||
sql = ''
|
|
||||||
if execute_flag and re.search(r'parameters: ', line, re.IGNORECASE):
|
|
||||||
execute_flag = False
|
|
||||||
param_list = re.search(r'parameters: (.*)', line.strip(),
|
|
||||||
re.IGNORECASE).group(1).split(', ')
|
|
||||||
param_list = list(param.split('=', 1) for param in param_list)
|
|
||||||
param_list.sort(key=lambda x: int(x[0].strip(' $')),
|
|
||||||
reverse=True)
|
|
||||||
for item in param_list:
|
|
||||||
if len(item[1].strip()) >= 256:
|
|
||||||
sql = sql.replace(item[0].strip(), "''")
|
|
||||||
else:
|
else:
|
||||||
sql = sql.replace(item[0].strip(), item[1].strip())
|
statement_flag = False
|
||||||
yield output_valid_sql(sql)
|
if output_valid_sql(sql):
|
||||||
sql = ''
|
yield output_valid_sql(sql)
|
||||||
|
sql = ''
|
||||||
|
if execute_flag and re.search(r'parameters: ', line, re.IGNORECASE):
|
||||||
|
execute_flag = False
|
||||||
|
param_list = re.search(r'parameters: (.*)', line.strip(),
|
||||||
|
re.IGNORECASE).group(1).split(', ')
|
||||||
|
param_list = list(param.split('=', 1) for param in param_list)
|
||||||
|
param_list.sort(key=lambda x: int(x[0].strip(' $')),
|
||||||
|
reverse=True)
|
||||||
|
for item in param_list:
|
||||||
|
if len(item[1].strip()) >= 256:
|
||||||
|
sql = sql.replace(item[0].strip(), "''")
|
||||||
|
else:
|
||||||
|
sql = sql.replace(item[0].strip(), item[1].strip())
|
||||||
|
yield output_valid_sql(sql)
|
||||||
|
sql = ''
|
||||||
|
line = f.readline()
|
||||||
|
except:
|
||||||
|
execute_flag = False
|
||||||
|
statement_flag = False
|
||||||
line = f.readline()
|
line = f.readline()
|
||||||
|
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user