← Back to team overview

maria-developers team mailing list archive

Re: MDEV-7950 Item_func::type() takes 0.26% in OLTP RO

 

Hi Alexander,

what if we do something like this:
static SEL_TREE *get_mm_tree_XXX(Item *arg1, Item *arg2)
{
  return !arg1->real_item()->type() == Item::FIELD_ITEM ||
         arg1->real_item()->const_item() ||
         arg2->is_expensive() ? 0 :
         get_full_func_mm_tree(param, this, (Item_field*) (arg1->real_item()), arg2, false);
}

then we should be able to do tricks like this:
  if (!(ftree= get_mm_tree_XXX(arguments()[0], arguments()[1])))
    ftree= get_mm_tree_XXX(arguments()[1], arguments()[0]);
  DBUG_RETURN(ftree);

Thanks,
Sergey

On Thu, May 28, 2015 at 08:25:57AM +0400, Alexander Barkov wrote:
> Hello Sergey,
> 
> Please review the next step for MDEV-7950.
> 
> It does the following:
> 
> - Adds specific implementations of virtual method get_mm_tree() into
>   Item_func_like, Item_bool_rowready_func2, Item_func_spatial_rel
> 
> - Gets rid of two virtual calls: select_optimize() and have_rev_func().
> 
> - Removes virtual methods Item_func::select_optimize(),
>   Item_func::have_rev_func(),
>   as well as enum Item_func::optimize_type,
>   because they are not needed any more.
> 
> Thanks.

> diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
> index 93e4788..57a88e3 100644
> --- a/sql/item_cmpfunc.cc
> +++ b/sql/item_cmpfunc.cc
> @@ -4806,22 +4806,21 @@ longlong Item_func_like::val_int()
>    We can optimize a where if first character isn't a wildcard
>  */
>  
> -Item_func::optimize_type Item_func_like::select_optimize() const
> +bool Item_func_like::is_sargable_pattern() const
>  {
>    if (!args[1]->const_item() || args[1]->is_expensive())
> -    return OPTIMIZE_NONE;
> +    return false;
>  
>    String* res2= args[1]->val_str((String *)&cmp.value2);
>    if (!res2)
> -    return OPTIMIZE_NONE;
> +    return false;
>  
>    if (!res2->length()) // Can optimize empty wildcard: column LIKE ''
> -    return OPTIMIZE_OP;
> +    return true;
>  
>    DBUG_ASSERT(res2->ptr());
>    char first= res2->ptr()[0];
> -  return (first == wild_many || first == wild_one) ?
> -    OPTIMIZE_NONE : OPTIMIZE_OP;
> +  return first != wild_many && first != wild_one;
>  }
>  
>  
> diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
> index 2f26e48..7e2c5a1 100644
> --- a/sql/item_cmpfunc.h
> +++ b/sql/item_cmpfunc.h
> @@ -304,10 +304,7 @@ class Item_bool_func2 :public Item_bool_func
>    {
>      return cmp.set_cmp_func(this, tmp_arg, tmp_arg+1, TRUE);
>    }
> -  optimize_type select_optimize() const { return OPTIMIZE_OP; }
>    virtual enum Functype rev_functype() const { return UNKNOWN_FUNC; }
> -  bool have_rev_func() const { return rev_functype() != UNKNOWN_FUNC; }
> -
>    virtual inline void print(String *str, enum_query_type query_type)
>    {
>      Item_func::print_op(str, query_type);
> @@ -355,6 +352,10 @@ class Item_bool_rowready_func2 :public Item_bool_func2
>      return add_key_fields_optimize_op(join, key_fields, and_level,
>                                        usable_tables, sargables, false);
>    }
> +  SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr)
> +  {
> +    return get_mm_tree_op2(param, true);
> +  }
>  };
>  
>  /**
> @@ -591,7 +592,6 @@ class Item_func_ne :public Item_bool_rowready_func2
>    longlong val_int();
>    enum Functype functype() const { return NE_FUNC; }
>    cond_result eq_cmp_result() const { return COND_FALSE; }
> -  optimize_type select_optimize() const { return OPTIMIZE_KEY; } 
>    const char *func_name() const { return "<>"; }
>    Item *negated_item();
>    void add_key_fields(JOIN *join, KEY_FIELD **key_fields, uint *and_level,
> @@ -642,7 +642,6 @@ class Item_func_between :public Item_func_opt_neg
>    Item_func_between(Item *a, Item *b, Item *c)
>      :Item_func_opt_neg(a, b, c), compare_as_dates(FALSE) { sargable= TRUE; }
>    longlong val_int();
> -  optimize_type select_optimize() const { return OPTIMIZE_KEY; }
>    enum Functype functype() const   { return BETWEEN; }
>    const char *func_name() const { return "between"; }
>    bool fix_fields(THD *, Item **);
> @@ -1334,8 +1333,6 @@ class Item_func_in :public Item_func_opt_neg
>      }
>      DBUG_VOID_RETURN;
>    }
> -  optimize_type select_optimize() const
> -    { return OPTIMIZE_KEY; }
>    void add_key_fields(JOIN *join, KEY_FIELD **key_fields, uint *and_level,
>                        table_map usable_tables, SARGABLE_PARAM **sargables);
>    SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr);
> @@ -1382,9 +1379,9 @@ class Item_func_null_predicate :public Item_bool_func
>  {
>  public:
>    Item_func_null_predicate(Item *a) :Item_bool_func(a) { sargable= true; }
> -  optimize_type select_optimize() const { return OPTIMIZE_NULL; }
>    void add_key_fields(JOIN *join, KEY_FIELD **key_fields, uint *and_level,
>                        table_map usable_tables, SARGABLE_PARAM **sargables);
> +  SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr);
>    CHARSET_INFO *compare_collation() const
>    { return args[0]->collation.collation; }
>    void fix_length_and_dec() { decimals=0; max_length=1; maybe_null=0; }
> @@ -1490,6 +1487,12 @@ class Item_func_like :public Item_bool_func2
>  
>    bool escape_used_in_parsing;
>    bool use_sampling;
> +  /**
> +    Determines if the LIKE pattern is suitable for range optimizer:
> +    It must be inexpensive const Item with no wildcards on the
> +    leftmost position.
> +  */
> +  bool is_sargable_pattern() const;
>  
>  public:
>    int escape;
> @@ -1500,7 +1503,11 @@ class Item_func_like :public Item_bool_func2
>       escape_used_in_parsing(escape_used), use_sampling(0) {}
>    longlong val_int();
>    enum Functype functype() const { return LIKE_FUNC; }
> -  optimize_type select_optimize() const;
> +  SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr)
> +  {
> +    return is_sargable_pattern() ? get_mm_tree_op2(param, false) :
> +                                   Item_func::get_mm_tree(param, cond_ptr);
> +  }
>    cond_result eq_cmp_result() const
>    {
>      /**
> @@ -1918,7 +1925,6 @@ class Item_equal: public Item_bool_func
>    enum Functype functype() const { return MULT_EQUAL_FUNC; }
>    longlong val_int(); 
>    const char *func_name() const { return "multiple equal"; }
> -  optimize_type select_optimize() const { return OPTIMIZE_EQUAL; }
>    void sort(Item_field_cmpfunc compare, void *arg);
>    void fix_length_and_dec();
>    bool fix_fields(THD *thd, Item **ref);
> diff --git a/sql/item_func.h b/sql/item_func.h
> index cb8975a..1dbd926 100644
> --- a/sql/item_func.h
> +++ b/sql/item_func.h
> @@ -41,6 +41,21 @@ class Item_func :public Item_func_or_sum, public Used_tables_and_const_cache
>    */
>    uint allowed_arg_cols;
>    String *val_str_from_val_str_ascii(String *str, String *str2);
> +  /**
> +    This method is invoked for binary operations:
> +    - Comparison operators:  <, <=, =, <=>, =>, >
> +    - LIKE
> +    - Spatial relation predicates: Crosses, Touches, Contains, Disjoint,
> +                                   Equals, Intersects, Overlaps, Within
> +    @param param        - Range optimizer context
> +    @param optimize_rev - Determines whether the range optimizer should try
> +                          to optimize REVERSE_OPERATION(const,field)
> +                          if the direct operation was not in the form:
> +                          OPERATION(field,const), e.g.
> +                              WHERE 10<field1  ->  WHERE field1>10
> +    @return             - select tree for the function
> +  */
> +  SEL_TREE *get_mm_tree_op2(RANGE_OPT_PARAM *param, bool optimize_rev);
>  public:
>    table_map not_null_tables_cache;
>  
> @@ -60,8 +75,6 @@ class Item_func :public Item_func_or_sum, public Used_tables_and_const_cache
>                    SUSERVAR_FUNC, GUSERVAR_FUNC, COLLATE_FUNC,
>                    EXTRACT_FUNC, CHAR_TYPECAST_FUNC, FUNC_SP, UDF_FUNC,
>                    NEG_FUNC, GSYSVAR_FUNC, DYNCOL_FUNC };
> -  enum optimize_type { OPTIMIZE_NONE,OPTIMIZE_KEY,OPTIMIZE_OP, OPTIMIZE_NULL,
> -                       OPTIMIZE_EQUAL };
>    enum Type type() const { return FUNC_ITEM; }
>    virtual enum Functype functype() const   { return UNKNOWN_FUNC; }
>    Item_func(void):
> @@ -136,8 +149,6 @@ class Item_func :public Item_func_or_sum, public Used_tables_and_const_cache
>                            COND_EQUAL **cond_equal_ref);
>    SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr);
>    bool eq(const Item *item, bool binary_cmp) const;
> -  virtual optimize_type select_optimize() const { return OPTIMIZE_NONE; }
> -  virtual bool have_rev_func() const { return 0; }
>    virtual Item *key_item() const { return args[0]; }
>    virtual bool const_item() const { return const_item_cache; }
>    void set_arguments(List<Item> &list)
> diff --git a/sql/item_geofunc.h b/sql/item_geofunc.h
> index 97001af..3024a14 100644
> --- a/sql/item_geofunc.h
> +++ b/sql/item_geofunc.h
> @@ -287,7 +287,6 @@ class Item_func_spatial_rel: public Item_bool_func
>    enum Functype functype() const { return spatial_rel; }
>    enum Functype rev_functype() const { return spatial_rel; }
>    bool is_null() { (void) val_int(); return null_value; }
> -  optimize_type select_optimize() const { return OPTIMIZE_OP; }
>    void add_key_fields(JOIN *join, KEY_FIELD **key_fields,
>                        uint *and_level, table_map usable_tables,
>                        SARGABLE_PARAM **sargables)
> @@ -295,6 +294,14 @@ class Item_func_spatial_rel: public Item_bool_func
>      return add_key_fields_optimize_op(join, key_fields, and_level,
>                                        usable_tables, sargables, false);
>    }
> +  SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr)
> +  {
> +    /*
> +     TODO:
> +     MDEV-8239 Reverse spatial operations OP(const, field) do not get optimized
> +    */
> +    return get_mm_tree_op2(param, false);
> +  }
>  };
>  
>  
> diff --git a/sql/opt_range.cc b/sql/opt_range.cc
> index 190cd45..e936755 100644
> --- a/sql/opt_range.cc
> +++ b/sql/opt_range.cc
> @@ -7812,10 +7812,19 @@ static SEL_TREE *get_func_mm_tree(RANGE_OPT_PARAM *param, Item_func *cond_func,
>    {
>      /* 
>         Here the function for the following predicates are processed:
> -       <, <=, =, >=, >, LIKE, IS NULL, IS NOT NULL.
> +       <, <=, =, >=, >, LIKE, IS NULL, IS NOT NULL, spatial relation predicates
>         If the predicate is of the form (value op field) it is handled
>         as the equivalent predicate (field rev_op value), e.g.
>         2 <= a is handled as a >= 2.
> +
> +       TODO:
> +       MDEV-8239 Reverse spatial operations OP(const, field) do not get optimized
> +       Currently, for spatial predicates:
> +       - field is always in arguments()[0]
> +       - value is always in arguments()[1].
> +       The below cast to Item_bool_func2 with a rev_functype() call will not
> +       be valid for spatial predicates when MDEV-8239 gets fixed and
> +       field/value start to be passed in the opposite order.
>      */
>      Item_func::Functype func_type=
>        (value != cond_func->arguments()[0]) ? cond_func->functype() :
> @@ -8200,14 +8209,49 @@ SEL_TREE *Item_equal::get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr)
>  }
>  
>  
> +/*
> +  This is invoked for the functions that cannot use range optimizer
> +*/
>  SEL_TREE *Item_func::get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr)
>  {
>    DBUG_ENTER("Item_func::get_mm_tree");
>    if (const_item())
>      DBUG_RETURN(get_mm_tree_for_const(param, this));
> +  DBUG_RETURN(0);
> +}
>  
> -  if (select_optimize() == Item_func::OPTIMIZE_NONE)
> -    DBUG_RETURN(0);
> +
> +SEL_TREE *
> +Item_func_null_predicate::get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr)
> +{
> +  DBUG_ENTER("Item_func_null_predicate::get_mm_tree");
> +  if (const_item())
> +    DBUG_RETURN(get_mm_tree_for_const(param, this));
> +
> +  param->cond= this;
> +  if (arguments()[0]->real_item()->type() == Item::FIELD_ITEM)
> +  {
> +    Item_field *field_item= (Item_field*) (arguments()[0]->real_item());
> +    if (!field_item->const_item())
> +      DBUG_RETURN(get_full_func_mm_tree(param, this, field_item, NULL, false));
> +  }
> +  DBUG_RETURN(NULL);
> +}
> +
> +
> +/*
> +  This method is invoked for binary operations:
> +  - Comparison operators:  <, <=, =, <=>, =>, >
> +  - LIKE
> +  - Spatial relation predicates: Crosses, Touches, Contains, Disjoint,
> +                                 Equals, Intersects, Overlaps, Within
> +*/
> +SEL_TREE *Item_func::get_mm_tree_op2(RANGE_OPT_PARAM *param, bool optimize_rev)
> +{
> +  DBUG_ENTER("Item_func::get_mm_tree_op2");
> +  DBUG_ASSERT(arg_count == 2);
> +  if (const_item())
> +    DBUG_RETURN(get_mm_tree_for_const(param, this));
>  
>    param->cond= this;
>  
> @@ -8215,7 +8259,7 @@ SEL_TREE *Item_func::get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr)
>    if (arguments()[0]->real_item()->type() == Item::FIELD_ITEM)
>    {
>      Item_field *field_item= (Item_field*) (arguments()[0]->real_item());
> -    Item *value= arg_count > 1 ? arguments()[1] : NULL;
> +    Item *value= arguments()[1];
>      if (value && value->is_expensive())
>        DBUG_RETURN(0);
>      if (!arguments()[0]->real_item()->const_item())
> @@ -8237,7 +8281,7 @@ SEL_TREE *Item_func::get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr)
>      call to get_full_func_mm_tree() with reversed operands (see
>      below) may succeed.
>    */
> -  if (!ftree && have_rev_func() &&
> +  if (!ftree && optimize_rev &&
>        arguments()[1]->real_item()->type() == Item::FIELD_ITEM)
>    {
>      Item_field *field_item= (Item_field*) (arguments()[1]->real_item());
> diff --git a/sql/sql_select.cc b/sql/sql_select.cc
> index dccad7a..b50433e 100644
> --- a/sql/sql_select.cc
> +++ b/sql/sql_select.cc
> @@ -4762,8 +4762,7 @@ Item_func_like::add_key_fields(JOIN *join, KEY_FIELD **key_fields,
>                                 uint *and_level, table_map usable_tables,
>                                 SARGABLE_PARAM **sargables)
>  {
> -  if (is_local_field(args[0]) &&
> -      Item_func_like::select_optimize() == OPTIMIZE_OP)
> +  if (is_local_field(args[0]) && is_sargable_pattern())
>    {
>      /*
>        SELECT * FROM t1 WHERE field LIKE const_pattern



References