null+****@clear*****
null+****@clear*****
2010年 10月 13日 (水) 04:08:35 JST
Kentoku SHIBA 2010-10-12 19:08:35 +0000 (Tue, 12 Oct 2010) New Revision: 76ced29454b08f19ec38bf4d31339847851025c9 Log: #444 count performance improvement Modified files: ha_mroonga.cc ha_mroonga.h Modified: ha_mroonga.cc (+330 -11) =================================================================== --- ha_mroonga.cc 2010-10-12 19:05:42 +0000 (f1ef7f5) +++ ha_mroonga.cc 2010-10-12 19:08:35 +0000 (196dc22) @@ -41,6 +41,10 @@ grn_obj *mrn_db; grn_hash *mrn_hash; pthread_mutex_t db_mutex; +/* status */ +st_mrn_statuses mrn_status_vals; +long mrn_count_skip = 0; + /* logging */ const char *mrn_logfile_name = MRN_LOG_FILE_NAME; FILE *mrn_logfile = NULL; @@ -66,12 +70,35 @@ grn_logger_info mrn_logger_info = { /* system functions */ +static void mrn_create_status() +{ + DBUG_ENTER("mrn_create_status"); + mrn_status_vals.count_skip = mrn_count_skip; + DBUG_VOID_RETURN; +} + +struct st_mysql_show_var mrn_statuses[] = +{ + {"count_skip", (char *) &mrn_status_vals.count_skip, SHOW_LONG}, + {NullS, NullS, SHOW_LONG} +}; + +static int mrn_show_status(THD *thd, SHOW_VAR *var, char *buff) +{ + DBUG_ENTER("mrn_show_status"); + mrn_create_status(); + var->type = SHOW_ARRAY; + var->value = (char *) &mrn_statuses; + DBUG_RETURN(0); +} + struct st_mysql_storage_engine storage_engine_structure = { MYSQL_HANDLERTON_INTERFACE_VERSION }; struct st_mysql_show_var mrn_status_variables[] = { - {NULL} + {"grn", (char *) &mrn_show_status, SHOW_FUNC}, + {NullS, NullS, SHOW_LONG} }; struct st_mysql_sys_var *mrn_system_variables[] = @@ -581,6 +608,7 @@ ha_mroonga::ha_mroonga(handlerton *hton, TABLE_SHARE *share) DBUG_ENTER("ha_mroonga::ha_mroonga"); ctx = grn_ctx_open(0); grn_ctx_use(ctx, mrn_db); + cur = NULL; DBUG_VOID_RETURN; } @@ -625,7 +653,7 @@ ulonglong ha_mroonga_table_flags = HA_REC_NOT_IN_SEQ | HA_NULL_IN_KEY | HA_CAN_INDEX_BLOBS | - //HA_STATS_RECORDS_IS_EXACT | + HA_STATS_RECORDS_IS_EXACT | HA_NO_PREFIX_CHAR_KEYS | HA_CAN_FULLTEXT | HA_NO_AUTO_INCREMENT | @@ -1033,6 +1061,7 @@ THR_LOCK_DATA **ha_mroonga::store_lock(THD *thd, THR_LOCK_DATA **to, int ha_mroonga::rnd_init(bool scan) { DBUG_ENTER("ha_mroonga::rnd_init"); + count_skip = FALSE; cur = grn_table_cursor_open(ctx, tbl, NULL, 0, NULL, 0, 0, -1, 0); if (cur == NULL) { GRN_LOG(ctx, GRN_LOG_ERROR, "cannot open cursor"); @@ -1041,12 +1070,24 @@ int ha_mroonga::rnd_init(bool scan) DBUG_RETURN(0); } +int ha_mroonga::rnd_end() +{ + DBUG_ENTER("ha_mroonga::rnd_end"); + if (cur) { + grn_table_cursor_close(ctx, cur); + cur = NULL; + } + DBUG_RETURN(0); +} + int ha_mroonga::rnd_next(uchar *buf) { DBUG_ENTER("ha_mroonga::rnd_next"); row_id = grn_table_cursor_next(ctx, cur); if (row_id == GRN_ID_NIL) { grn_table_cursor_close(ctx, cur); + cur = NULL; + table->status = STATUS_NOT_FOUND; DBUG_RETURN(HA_ERR_END_OF_FILE); } store_fields_from_primary_table(row_id); @@ -1137,6 +1178,7 @@ int ha_mroonga::update_row(const uchar *old_data, uchar *new_data) my_bitmap_map *tmp_map = dbug_tmp_use_all_columns(table, table->read_set); #endif + DBUG_PRINT("info",("mroonga update column %d(%d)",i,field->field_index)); mrn_set_buf(ctx, field, &colbuf, &col_size); if (grn_obj_set_value(ctx, col[i], row_id, &colbuf, GRN_OBJ_SET) != GRN_SUCCESS) { @@ -1177,14 +1219,14 @@ ha_rows ha_mroonga::records_in_range(uint keynr, key_range *range_min, key_range if (range_min != NULL) { mrn_set_key_buf(ctx, field, range_min->key, key_min[keynr], &size_min); val_min = key_min[keynr]; - if (range_min->flag & HA_READ_AFTER_KEY) { + if (range_min->flag == HA_READ_AFTER_KEY) { flags |= GRN_CURSOR_GT; } } if (range_max != NULL) { mrn_set_key_buf(ctx, field, range_max->key, key_max[keynr], &size_max); val_max = key_max[keynr]; - if (range_max->flag & HA_READ_BEFORE_KEY) { + if (range_max->flag == HA_READ_BEFORE_KEY) { flags |= GRN_CURSOR_LT; } } @@ -1213,6 +1255,24 @@ ha_rows ha_mroonga::records_in_range(uint keynr, key_range *range_min, key_range DBUG_RETURN(row_count); } +int ha_mroonga::index_init(uint idx, bool sorted) +{ + DBUG_ENTER("ha_mroonga::index_init"); + active_index = idx; + count_skip = FALSE; + DBUG_RETURN(0); +} + +int ha_mroonga::index_end() +{ + DBUG_ENTER("ha_mroonga::index_end"); + if (cur) { + grn_table_cursor_close(ctx, cur); + cur = NULL; + } + DBUG_RETURN(0); +} + int ha_mroonga::index_read_map(uchar * record_buffer, const uchar * key, key_part_map keypart_map, enum ha_rkey_function find_flag) @@ -1223,9 +1283,67 @@ int ha_mroonga::index_read_map(uchar * record_buffer, const uchar * key, uint pkeynr = table->s->primary_key; KEY key_info = table->key_info[keynr]; KEY_PART_INFO key_part = key_info.key_part[0]; - if (keynr == pkeynr) { - row_id = grn_table_get(ctx, tbl, key, key_len); - store_fields_from_primary_table(row_id); + check_count_skip(keypart_map, 0, FALSE); + if (count_skip) { + int flags = 0; + uint size_min = 0, size_max = 0; + void *val_min = NULL, *val_max = NULL; + Field *field = key_part.field; + + if (cur) { + grn_table_cursor_close(ctx, cur); + cur = NULL; + } + + if (find_flag == HA_READ_KEY_EXACT) { + mrn_set_key_buf(ctx, field, key, key_min[keynr], &size_min); + val_min = key_min[keynr]; + val_max = key_min[keynr]; + size_max = size_min; + } else if ( + find_flag == HA_READ_BEFORE_KEY || + find_flag == HA_READ_PREFIX_LAST_OR_PREV + ) { + mrn_set_key_buf(ctx, field, key, key_max[keynr], &size_max); + val_max = key_max[keynr]; + if (find_flag == HA_READ_BEFORE_KEY) { + flags |= GRN_CURSOR_LT; + } + } else { + mrn_set_key_buf(ctx, field, key, key_min[keynr], &size_min); + val_min = key_min[keynr]; + if (find_flag == HA_READ_AFTER_KEY) { + flags |= GRN_CURSOR_GT; + } + } + + uint pkeynr = table->s->primary_key; + + if (keynr == pkeynr) { // primary index + cur = + grn_table_cursor_open(ctx, tbl, val_min, size_min, val_max, size_max, + 0, -1, flags); + } else { // normal index + cur = + grn_table_cursor_open(ctx, idx_tbl[keynr], val_min, size_min, + val_max, size_max, 0, -1, flags); + } + row_id = grn_table_cursor_next(ctx, cur); + if (row_id == GRN_ID_NIL) { + grn_table_cursor_close(ctx, cur); + cur = NULL; + table->status = STATUS_NOT_FOUND; + DBUG_RETURN(HA_ERR_END_OF_FILE); + } + if (keynr == pkeynr) { // primary index + /* store only for first time */ + store_fields_from_primary_table(row_id); + } + } else { + if (keynr == pkeynr) { + row_id = grn_table_get(ctx, tbl, key, key_len); + store_fields_from_primary_table(row_id); + } } table->status = 0; DBUG_RETURN(0); @@ -1244,6 +1362,8 @@ int ha_mroonga::index_next(uchar *buf) row_id = grn_table_cursor_next(ctx, cur); if (row_id == GRN_ID_NIL) { grn_table_cursor_close(ctx, cur); + cur = NULL; + table->status = STATUS_NOT_FOUND; DBUG_RETURN(HA_ERR_END_OF_FILE); } store_fields_from_primary_table(row_id); @@ -1254,21 +1374,126 @@ int ha_mroonga::index_next(uchar *buf) int ha_mroonga::index_prev(uchar *buf) { DBUG_ENTER("ha_mroonga::index_prev"); + table->status = STATUS_NOT_FOUND; DBUG_RETURN(HA_ERR_END_OF_FILE); } int ha_mroonga::index_first(uchar *buf) { DBUG_ENTER("ha_mroonga::index_first"); + table->status = STATUS_NOT_FOUND; DBUG_RETURN(HA_ERR_END_OF_FILE); } int ha_mroonga::index_last(uchar *buf) { DBUG_ENTER("ha_mroonga::index_last"); + table->status = STATUS_NOT_FOUND; DBUG_RETURN(HA_ERR_END_OF_FILE); } +int ha_mroonga::index_next_same(uchar *buf, const uchar *key, uint keylen) +{ + DBUG_ENTER("ha_mroonga::index_next_same"); + if (count_skip) { + row_id = grn_table_cursor_next(ctx, cur); + + if (row_id == GRN_ID_NIL) { + grn_table_cursor_close(ctx, cur); + cur = NULL; + table->status = STATUS_NOT_FOUND; + DBUG_RETURN(HA_ERR_END_OF_FILE); + } + table->status = 0; + DBUG_RETURN(0); + } else { + DBUG_RETURN(handler::index_next_same(buf, key, keylen)); + } +} + +int ha_mroonga::read_range_first(const key_range *start_key, + const key_range *end_key, + bool eq_range, bool sorted) +{ + DBUG_ENTER("ha_mroonga::read_range_first"); + check_count_skip(start_key ? start_key->keypart_map : 0, + end_key ? end_key->keypart_map : 0, FALSE); + int flags = 0; + uint size_min = 0, size_max = 0; + void *val_min = NULL, *val_max = NULL; + KEY key_info = table->s->key_info[active_index]; + KEY_PART_INFO key_part = key_info.key_part[0]; + Field *field = key_part.field; + + if (cur) { + grn_table_cursor_close(ctx, cur); + cur = NULL; + } + + if (start_key != NULL) { + mrn_set_key_buf(ctx, field, start_key->key, key_min[active_index], + &size_min); + val_min = key_min[active_index]; + if (start_key->flag == HA_READ_AFTER_KEY) { + flags |= GRN_CURSOR_GT; + } + } + if (end_key != NULL) { + mrn_set_key_buf(ctx, field, end_key->key, key_max[active_index], + &size_max); + val_max = key_max[active_index]; + if (end_key->flag == HA_READ_BEFORE_KEY) { + flags |= GRN_CURSOR_LT; + } + } + uint pkeynr = table->s->primary_key; + + if (active_index == pkeynr) { // primary index + DBUG_PRINT("info",("mroonga use primary key")); + cur = + grn_table_cursor_open(ctx, tbl, val_min, size_min, val_max, size_max, + 0, -1, flags); + } else { // normal index + DBUG_PRINT("info",("mroonga use key%u", active_index)); + cur = + grn_table_cursor_open(ctx, idx_tbl[active_index], val_min, size_min, + val_max, size_max, 0, -1, flags); + } + row_id = grn_table_cursor_next(ctx, cur); + if (row_id == GRN_ID_NIL) { + grn_table_cursor_close(ctx, cur); + cur = NULL; + table->status = STATUS_NOT_FOUND; + DBUG_RETURN(HA_ERR_END_OF_FILE); + } + if (active_index == pkeynr) { // primary index + store_fields_from_primary_table(row_id); + } + table->status = 0; + DBUG_RETURN(0); +} + +int ha_mroonga::read_range_next() { + DBUG_ENTER("ha_mroonga::read_range_next"); + row_id = grn_table_cursor_next(ctx, cur); + + if (row_id == GRN_ID_NIL) { + grn_table_cursor_close(ctx, cur); + cur = NULL; + table->status = STATUS_NOT_FOUND; + DBUG_RETURN(HA_ERR_END_OF_FILE); + } + + uint pkeynr = table->s->primary_key; + if (!count_skip) { + if (active_index == pkeynr) { // primary index + store_fields_from_primary_table(row_id); + } + } + table->status = 0; + DBUG_RETURN(0); +} + int ha_mroonga::ft_init() { DBUG_ENTER("ha_mroonga::ft_init"); DBUG_RETURN(0); @@ -1280,6 +1505,8 @@ FT_INFO *ha_mroonga::ft_init_ext(uint flags, uint keynr, String *key) grn_obj *ft = idx_col[keynr]; const char *keyword = key->ptr(); int keyword_size = strlen(keyword); + check_count_skip(0, 0, TRUE); + row_id = GRN_ID_NIL; res = grn_table_create(ctx, NULL, 0, NULL, GRN_TABLE_HASH_KEY, tbl, 0); @@ -1309,18 +1536,19 @@ int ha_mroonga::ft_read(uchar *buf) if (rid == GRN_ID_NIL) { grn_table_cursor_close(ctx, cur); + cur = NULL; grn_obj_unlink(ctx, res); + table->status = STATUS_NOT_FOUND; DBUG_RETURN(HA_ERR_END_OF_FILE); } + table->status = 0; - if (table->in_use->lex->select_lex.join->tmp_table_param.sum_func_count > 0) { + if (count_skip && row_id != GRN_ID_NIL) { DBUG_RETURN(0); } grn_table_get_key(ctx, res, rid, &row_id, sizeof(grn_id)); - store_fields_from_primary_table(row_id); - table->status = 0; DBUG_RETURN(0); } @@ -1344,9 +1572,99 @@ bool ha_mroonga::get_error_message(int error, String *buf) DBUG_RETURN(FALSE); } +void ha_mroonga::check_count_skip(key_part_map start_key_part_map, + key_part_map end_key_part_map, bool fulltext) +{ + DBUG_ENTER("ha_mroonga::check_count_skip"); + st_select_lex *select_lex = table->pos_in_table_list->select_lex; + + if ( + thd_sql_command(ha_thd()) == SQLCOM_SELECT && + !select_lex->non_agg_fields.elements && + !select_lex->group_list.elements && + !select_lex->having && + select_lex->table_list.elements == 1 + ) { + Item *info = (Item *) select_lex->item_list.first_node()->info; + if ( + info->type() != Item::SUM_FUNC_ITEM || + ((Item_sum *) info)->sum_func() != Item_sum::COUNT_FUNC || + ((Item_sum *) info)->nest_level || + ((Item_sum *) info)->aggr_level || + ((Item_sum *) info)->max_arg_level != -1 || + ((Item_sum *) info)->max_sum_func_level != -1 + ) { + count_skip = FALSE; + DBUG_VOID_RETURN; + } + + int i = 0; + Item *where; + if (fulltext) { + where = select_lex->where; + if (!where || + where->type() != Item::FUNC_ITEM || + ((Item_func *)where)->functype() != Item_func::FT_FUNC) { + count_skip = FALSE; + DBUG_VOID_RETURN; + } + where = where->next; + if (!where || + where->type() != Item::STRING_ITEM) { + count_skip = FALSE; + DBUG_VOID_RETURN; + } + for (where = where->next; where; where = where->next) { + if (where->type() != Item::FIELD_ITEM) + break; + } + if (where != info) { + count_skip = FALSE; + DBUG_VOID_RETURN; + } + count_skip = TRUE; + mrn_count_skip++; + DBUG_VOID_RETURN; + } else { + uint keynr = active_index; + KEY key_info = table->key_info[keynr]; + KEY_PART_INFO *key_part = key_info.key_part; + for (where = select_lex->where; where; where = where->next) { + if (where->type() == Item::FIELD_ITEM) + { + Field *field = ((Item_field *)where)->field; + if (field->table != table) + break; + int j; + for (j = 0; j < key_info.key_parts; j++) { + if (key_part[j].field == field) + { + if (!(start_key_part_map >> j) && !(end_key_part_map >> j)) + j = key_info.key_parts; + else + i++; + break; + } + } + if (j >= key_info.key_parts) + break; + } + if (i >= select_lex->select_n_where_fields) + { + count_skip = TRUE; + mrn_count_skip++; + DBUG_VOID_RETURN; + } + } + } + } + count_skip = FALSE; + DBUG_VOID_RETURN; +} + void ha_mroonga::store_fields_from_primary_table(grn_id rid) { - DBUG_ENTER("ha_mroonga::records_in_range"); + DBUG_ENTER("ha_mroonga::store_fields_from_primary_table"); int i; int n_columns = table->s->fields; for (i = 0; i < n_columns; i++) { @@ -1357,6 +1675,7 @@ void ha_mroonga::store_fields_from_primary_table(grn_id rid) my_bitmap_map *tmp_map = dbug_tmp_use_all_columns(table, table->write_set); #endif + DBUG_PRINT("info",("mroonga store column %d(%d)",i,field->field_index)); mrn_store_field(ctx, field, col[i], rid); #ifndef DBUG_OFF dbug_tmp_restore_column_map(table->write_set, tmp_map); Modified: ha_mroonga.h (+20 -1) =================================================================== --- ha_mroonga.h 2010-10-12 19:05:42 +0000 (421a75d) +++ ha_mroonga.h 2010-10-12 19:08:35 +0000 (be3d713) @@ -31,6 +31,12 @@ extern "C" { #include <groonga.h> #include "mrnsys.h" +/* structs */ +struct st_mrn_statuses +{ + long count_skip; +}; + /* functions */ int mrn_init(void *hton); int mrn_deinit(void *hton); @@ -61,6 +67,8 @@ class ha_mroonga: public handler int *key_min_len; int *key_max_len; + bool count_skip; + public: ha_mroonga(handlerton *hton, TABLE_SHARE *share); ~ha_mroonga(); @@ -81,6 +89,7 @@ public: enum thr_lock_type lock_type); int rnd_init(bool scan); // required + int rnd_end(); int rnd_next(uchar *buf); // required int rnd_pos(uchar *buf, uchar *pos); // required void position(const uchar *record); // required @@ -96,6 +105,8 @@ public: uint max_supported_key_length() const { return MAX_KEY_LENGTH; } ha_rows records_in_range(uint inx, key_range *min_key, key_range *max_key); + int index_init(uint idx, bool sorted); + int index_end(); int index_read_map(uchar * record_buffer, const uchar * key, key_part_map keypart_map, enum ha_rkey_function find_flag); @@ -105,7 +116,13 @@ public: int index_prev(uchar * buf); int index_first(uchar * buf); int index_last(uchar * buf); - + int index_next_same(uchar *buf, const uchar *key, uint keylen); + + int read_range_first(const key_range *start_key, + const key_range *end_key, + bool eq_range, bool sorted); + int read_range_next(); + int ft_init(); FT_INFO *ft_init_ext(uint flags, uint inx,String *key); int ft_read(uchar *buf); @@ -116,6 +133,8 @@ public: bool get_error_message(int error, String *buf); private: + void check_count_skip(key_part_map start_key_part_map, + key_part_map end_key_part_map, bool fulltext); void store_fields_from_primary_table(grn_id rid); };