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);
};