Commit 2a7cf59f authored by unknown's avatar unknown
Browse files

Fixed bug #21727.

This is a performance issue for queries with subqueries evaluation
of which requires filesort.
Allocation of memory for the sort buffer at each evaluation of a
subquery may take a significant amount of time if the buffer is rather big.
With the fix we allocate the buffer at the first evaluation of the
subquery and reuse it at each subsequent evaluation.


mysql-test/r/subselect.result:
  Added a test case for bug #21727.
mysql-test/t/subselect.test:
  Added a test case for bug #21727.
sql/item_subselect.h:
  Fixed bug #21727.
  This is a performance issue for queries with subqueries evaluation
  of which requires filesort.
  Added an implementation for Item_subselect::is_uncacheable()
  returning TRUE if the engine if the subselect is uncacheable.
sql/mysql_priv.h:
  Fixed bug #21727.
  This is a performance issue for queries with subqueries evaluation
  of which requires filesort.
  Added a new boolean parameter to the filesort_free_buffers procedure.
  If the value of this parameter is TRUE the procedure frees the sort_keys
  buffpek buffers.
sql/records.cc:
  Fixed bug #21727.
  This is a performance issue for queries with subqueries evaluation
  of which requires filesort.
  Added a new boolean parameter to the filesort_free_buffers procedure.
  If the value of this parameter is TRUE the procedure frees the sort_keys
  buffpek buffers.
sql/sql_base.cc:
  Fixed bug #21727.
  Made sure that st_table::pos_in_table_list would be always initialized.
sql/sql_select.cc:
  Fixed bug #21727.
  This is a performance issue for queries with subqueries evaluation
  of which requires filesort.
  Added a new boolean parameter to the filesort_free_buffers procedure.
  If the value of this parameter is TRUE the procedure frees the sort_keys
  buffpek buffers.
sql/sql_show.cc:
  Fixed bug #21727.
  This is a performance issue for queries with subqueries evaluation
  of which requires filesort.
  Added a new boolean parameter to the filesort_free_buffers procedure.
  If the value of this parameter is TRUE the procedure frees the sort_keys
  buffpek buffers.
sql/sql_table.cc:
  Fixed bug #21727.
  This is a performance issue for queries with subqueries evaluation
  of which requires filesort.
  Cleanup.
sql/table.cc:
  Fixed bug #21727.
  This is a performance issue for queries with subqueries evaluation
  of which requires filesort.
  Added st_table_list::in_subselect() returning for a table the subselect that 
  contains the FROM list this table is taken from (if there is any).
sql/table.h:
  Fixed bug #21727.
  This is a performance issue for queries with subqueries evaluation
  of which requires filesort.
  Added fields for sort_keys and buffpek buffers to the FILESORT_INFO structure.
parent e2698fa7
Loading
Loading
Loading
Loading
+16 −0
Original line number Diff line number Diff line
@@ -3545,3 +3545,19 @@ FROM t1 GROUP BY t1.a LIMIT 1)
2
2
DROP TABLE t1,t2;
CREATE TABLE t1 (a int, b int auto_increment, PRIMARY KEY (b));
CREATE TABLE t2 (x int auto_increment, y int, z int,
PRIMARY KEY (x), FOREIGN KEY (y) REFERENCES t1 (b));
SET SESSION sort_buffer_size = 32 * 1024;
SELECT SQL_NO_CACHE COUNT(*) 
FROM (SELECT  a, b, (SELECT x FROM t2 WHERE y=b ORDER BY z DESC LIMIT 1) c
FROM t1) t;
COUNT(*)
3000
SET SESSION sort_buffer_size = 8 * 1024 * 1024;
SELECT SQL_NO_CACHE COUNT(*) 
FROM (SELECT  a, b, (SELECT x FROM t2 WHERE y=b ORDER BY z DESC LIMIT 1) c
FROM t1) t;
COUNT(*)
3000
DROP TABLE t1,t2;
+37 −0
Original line number Diff line number Diff line
@@ -2426,3 +2426,40 @@ SELECT (
FROM t1 t2
GROUP BY t2.a;
DROP TABLE t1,t2;  

#
# Bug #21727: Correlated subquery that requires filesort:
#             slow with big sort_buffer_size 
#

CREATE TABLE t1 (a int, b int auto_increment, PRIMARY KEY (b));
CREATE TABLE t2 (x int auto_increment, y int, z int,
                 PRIMARY KEY (x), FOREIGN KEY (y) REFERENCES t1 (b));

disable_query_log;
let $1=3000;
while ($1)
{
  eval INSERT INTO t1(a) VALUES(RAND()*1000);
  eval SELECT MAX(b) FROM t1 INTO @id;
  let $2=10;
  while ($2)
  {
    eval INSERT INTO t2(y,z) VALUES(@id,RAND()*1000);
    dec $2;
  } 
  dec $1;
}
enable_query_log;

SET SESSION sort_buffer_size = 32 * 1024;
SELECT SQL_NO_CACHE COUNT(*) 
  FROM (SELECT  a, b, (SELECT x FROM t2 WHERE y=b ORDER BY z DESC LIMIT 1) c
          FROM t1) t;

SET SESSION sort_buffer_size = 8 * 1024 * 1024;
SELECT SQL_NO_CACHE COUNT(*) 
  FROM (SELECT  a, b, (SELECT x FROM t2 WHERE y=b ORDER BY z DESC LIMIT 1) c
          FROM t1) t;

DROP TABLE t1,t2;
+34 −7
Original line number Diff line number Diff line
@@ -109,6 +109,8 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
  DBUG_PUSH("");		/* No DBUG here */
#endif
  FILESORT_INFO table_sort;
  TABLE_LIST *tab= table->pos_in_table_list;
  Item_subselect *subselect= tab ? tab->containing_subselect() : 0;
  /* 
    Don't use table->sort in filesort as it is also used by 
    QUICK_INDEX_MERGE_SELECT. Work with a copy and put it back at the end 
@@ -121,7 +123,6 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
  my_b_clear(&tempfile);
  my_b_clear(&buffpek_pointers);
  buffpek=0;
  sort_keys= (uchar **) NULL;
  error= 1;
  bzero((char*) &param,sizeof(param));
  param.sort_length= sortlength(thd, sortorder, s_length, &multi_byte_charset);
@@ -202,13 +203,15 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
    ulong old_memavl;
    ulong keys= memavl/(param.rec_length+sizeof(char*));
    param.keys=(uint) min(records+1, keys);
    if ((sort_keys= (uchar **) make_char_array(param.keys, param.rec_length,
    if (table_sort.sort_keys ||
        (table_sort.sort_keys= (uchar **) make_char_array(param.keys, param.rec_length,
                                               MYF(0))))
      break;
    old_memavl=memavl;
    if ((memavl=memavl/4*3) < min_sort_memory && old_memavl > min_sort_memory)
      memavl= min_sort_memory;
  }
  sort_keys= table_sort.sort_keys;
  if (memavl < min_sort_memory)
  {
    my_error(ER_OUTOFMEMORY,MYF(ME_ERROR+ME_WAITTANG),
@@ -235,8 +238,12 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
  }
  else
  {
    if (!(buffpek=read_buffpek_from_file(&buffpek_pointers, maxbuffer)))
    if (!table_sort.buffpek && table_sort.buffpek_len < maxbuffer &&
        !(table_sort.buffpek=
          (byte *) read_buffpek_from_file(&buffpek_pointers, maxbuffer)))
      goto err;
    buffpek= (BUFFPEK *) table_sort.buffpek;
    table_sort.buffpek_len= maxbuffer;
    close_cached_file(&buffpek_pointers);
	/* Open cached file if it isn't open */
    if (! my_b_inited(outfile) &&
@@ -269,8 +276,14 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
 err:
  if (param.tmp_buffer)
    x_free(param.tmp_buffer);
  if (!subselect || !subselect->is_uncacheable())
  {
    x_free((gptr) sort_keys);
    table_sort.sort_keys= 0;
    x_free((gptr) buffpek);
    table_sort.buffpek= 0;
    table_sort.buffpek_len= 0;
  }
  close_cached_file(&tempfile);
  close_cached_file(&buffpek_pointers);
  if (my_b_inited(outfile))
@@ -301,13 +314,27 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
} /* filesort */


void filesort_free_buffers(TABLE *table)
void filesort_free_buffers(TABLE *table, bool full)
{
  if (table->sort.record_pointers)
  {
    my_free((gptr) table->sort.record_pointers,MYF(0));
    table->sort.record_pointers=0;
  }
  if (full)
  {
    if (table->sort.sort_keys )
    {
      x_free((gptr) table->sort.sort_keys);
      table->sort.sort_keys= 0;
    }
    if (table->sort.buffpek)
    {
      x_free((gptr) table->sort.buffpek);
      table->sort.buffpek= 0;
      table->sort.buffpek_len= 0;
    }
  }
  if (table->sort.addon_buf)
  {
    my_free((char *) table->sort.addon_buf, MYF(0));
+7 −0
Original line number Diff line number Diff line
@@ -114,6 +114,7 @@ class Item_subselect :public Item_result_field
    single select and union subqueries only.
  */
  bool is_evaluated() const;
  bool is_uncacheable() const;

  /*
    Used by max/min subquery to initialize value presence registration
@@ -428,3 +429,9 @@ inline bool Item_subselect::is_evaluated() const
  return engine->is_executed();
}

inline bool Item_subselect::is_uncacheable() const
{
  return engine->uncacheable();
}

+1 −1
Original line number Diff line number Diff line
@@ -1465,7 +1465,7 @@ void end_read_record(READ_RECORD *info);
ha_rows filesort(THD *thd, TABLE *form,struct st_sort_field *sortorder,
		 uint s_length, SQL_SELECT *select,
		 ha_rows max_rows, ha_rows *examined_rows);
void filesort_free_buffers(TABLE *table);
void filesort_free_buffers(TABLE *table, bool full);
void change_double_for_sort(double nr,byte *to);
double my_double_round(double value, int dec, bool truncate);
int get_quick_record(SQL_SELECT *select);
Loading