mariadb/storage/sphinx/ha_sphinx.h
Monty d9d0e78039 Add limits for how many IO operations a table access will do
This solves the current problem in the optimizer
- SELECT FROM big_table
  - SELECT from small_table where small_table.eq_ref_key=big_table.id

The old code assumed that each eq_ref access will cause an IO.
As the cost of IO is high, this dominated the cost for the later table
which caused the optimizer to prefer table scans + join cache over
index reads.

This patch fixes this issue by limit the number of expected IO calls,
for rows and index separately, to the size of the table or index or
the number of accesses that we except in a range for the index.

The major changes are:

- Adding a new structure ALL_READ_COST that is mainly used in
  best_access_path() to hold the costs parts of the cost we are
  calculating. This allows us to limit the number of IO when multiplying
  the cost with the previous row combinations.
- All storage engine cost functions are changed to return IO_AND_CPU_COST.
  The virtual cost functions should now return in IO_AND_CPU_COST.io
  the number of disk blocks that will be accessed instead of the cost
  of the access.
- We are not limiting the io_blocks for table or index scans as we
  assume that engines may not store these in the 'hot' part of the
  cache. Table and index scan also uses much less IO blocks than
  key accesses, so the original issue is not as critical with scans.

Other things:
  OPT_RANGE now holds a 'Cost_estimate cost' instead a lot of different
  costs. All the old costs, like index_only_read, can be extracted
  from 'cost'.
- Added to the start of some functions 'handler *file= table->file'
  to shorten the code that is using the handler.
- handler->cost() is used to change a ALL_READ_COST or IO_AND_CPU_COST
  to 'cost in milliseconds'
- New functions:  handler::index_blocks() and handler::row_blocks()
  which are used to limit the IO.
- Added index_cost and row_cost to Cost_estimate and removed all not
  needed members.
- Removed cost coefficients from Cost_estimate as these don't make sense
  when costs (except IO_BLOCKS) are in milliseconds.
- Removed handler::avg_io_cost() and replaced it with DISK_READ_COST.
- Renamed best_range_rowid_filter_for_partial_join() to
  best_range_rowid_filter() as using the old name made rows too long.
- Changed all SJ_MATERIALIZATION_INFO 'Cost_estimate' variables to
  'double' as Cost_estimate power was not used for these and thus
  just caused storage and performance overhead.
- Changed cost_for_index_read() to use 'worst_seeks' to only limit
  IO, not number of table accesses. With this patch worst_seeks is
  probably not needed anymore, but I kept it around just in case.
- Applying cost for filter got to be much shorter and easier thanks
  to the API changes.
- Adjusted cost for fulltext keys in collaboration with Sergei Golubchik.
- Most test changes caused by this patch is that table scans are changed
  to use indexes.
- Added ha_seq::keyread_time() and ha_seq::key_scan_time() to get
  make checking number of potential IO blocks easier during debugging.
2023-02-02 23:57:30 +03:00

189 lines
5.6 KiB
C++

//
// $Id: ha_sphinx.h 4818 2014-09-24 08:53:38Z tomat $
//
#ifdef USE_PRAGMA_INTERFACE
#pragma interface // gcc class implementation
#endif
#if MYSQL_VERSION_ID>=50515
#define TABLE_ARG TABLE_SHARE
#elif MYSQL_VERSION_ID>50100
#define TABLE_ARG st_table_share
#else
#define TABLE_ARG st_table
#endif
#if MYSQL_VERSION_ID>=50120
typedef uchar byte;
#endif
/// forward decls
class THD;
struct CSphReqQuery;
struct CSphSEShare;
struct CSphSEAttr;
struct CSphSEStats;
struct CSphSEThreadTable;
/// Sphinx SE handler class
class ha_sphinx final : public handler
{
protected:
THR_LOCK_DATA m_tLock; ///< MySQL lock
CSphSEShare * m_pShare; ///< shared lock info
uint m_iMatchesTotal;
uint m_iCurrentPos;
const byte * m_pCurrentKey;
uint m_iCurrentKeyLen;
char * m_pResponse; ///< searchd response storage
char * m_pResponseEnd; ///< searchd response storage end (points to wilderness!)
char * m_pCur; ///< current position into response
bool m_bUnpackError; ///< any errors while unpacking response
public:
#if MYSQL_VERSION_ID<50100
ha_sphinx ( TABLE_ARG * table_arg ); // NOLINT
#else
ha_sphinx ( handlerton * hton, TABLE_ARG * table_arg );
#endif
~ha_sphinx ();
const char * table_type () const { return "SPHINX"; } ///< SE name for display purposes
const char * index_type ( uint ) { return "HASH"; } ///< index type name for display purposes
#if MYSQL_VERSION_ID>50100
ulonglong table_flags () const { return HA_CAN_INDEX_BLOBS |
HA_CAN_TABLE_CONDITION_PUSHDOWN; } ///< bitmap of implemented flags (see handler.h for more info)
#else
ulong table_flags () const { return HA_CAN_INDEX_BLOBS; } ///< bitmap of implemented flags (see handler.h for more info)
#endif
ulong index_flags ( uint, uint, bool ) const { return 0; } ///< bitmap of flags that says how SE implements indexes
uint max_supported_record_length () const { return HA_MAX_REC_LENGTH; }
uint max_supported_keys () const { return 1; }
uint max_supported_key_parts () const { return 1; }
uint max_supported_key_length () const { return MAX_KEY_LENGTH; }
uint max_supported_key_part_length () const { return MAX_KEY_LENGTH; }
IO_AND_CPU_COST scan_time ()
{
IO_AND_CPU_COST cost;
cost.io= 0;
cost.cpu= (double) (stats.records+stats.deleted) * DISK_READ_COST;
return cost;
}
IO_AND_CPU_COST keyread_time(uint index, ulong ranges, ha_rows rows,
ulonglong blocks)
{
IO_AND_CPU_COST cost;
cost.io= ranges;
cost.cpu= 0;
return cost;
}
IO_AND_CPU_COST rnd_pos_time(ha_rows rows)
{
IO_AND_CPU_COST cost;
cost.io= 0;
cost.cpu= 0;
return cost;
}
public:
int open ( const char * name, int mode, uint test_if_locked );
int close ();
int write_row ( const byte * buf );
int update_row ( const byte * old_data, const byte * new_data );
int delete_row ( const byte * buf );
int extra ( enum ha_extra_function op );
int index_init ( uint keynr, bool sorted ); // 5.1.x
int index_init ( uint keynr ) { return index_init ( keynr, false ); } // 5.0.x
int index_end ();
int index_read ( byte * buf, const byte * key, uint key_len, enum ha_rkey_function find_flag );
int index_read_idx ( byte * buf, uint idx, const byte * key, uint key_len, enum ha_rkey_function find_flag );
int index_next ( byte * buf );
int index_next_same ( byte * buf, const byte * key, uint keylen );
int index_prev ( byte * buf );
int index_first ( byte * buf );
int index_last ( byte * buf );
int get_rec ( byte * buf, const byte * key, uint keylen );
int rnd_init ( bool scan );
int rnd_end ();
int rnd_next ( byte * buf );
int rnd_pos ( byte * buf, byte * pos );
void position ( const byte * record );
#if MYSQL_VERSION_ID>=50030
int info ( uint );
#else
void info ( uint );
#endif
int reset();
int external_lock ( THD * thd, int lock_type );
int delete_all_rows ();
ha_rows records_in_range ( uint inx, const key_range * min_key, const key_range * max_key, page_range *pages);
int delete_table ( const char * from );
int rename_table ( const char * from, const char * to );
int create ( const char * name, TABLE * form, HA_CREATE_INFO * create_info );
THR_LOCK_DATA ** store_lock ( THD * thd, THR_LOCK_DATA ** to, enum thr_lock_type lock_type );
public:
#if MYSQL_VERSION_ID<50610
virtual const COND * cond_push ( const COND *cond );
#else
virtual const Item * cond_push ( const Item *cond );
#endif
virtual void cond_pop ();
private:
uint32 m_iFields;
char ** m_dFields;
uint32 m_iAttrs;
CSphSEAttr * m_dAttrs;
int m_bId64;
int * m_dUnboundFields;
private:
int Connect ( const char * sQueryHost, ushort uPort );
int ConnectAPI ( const char * sQueryHost, int iQueryPort );
int HandleMysqlError ( struct st_mysql * pConn, int iErrCode );
uint32 UnpackDword ();
char * UnpackString ();
bool UnpackSchema ();
bool UnpackStats ( CSphSEStats * pStats );
bool CheckResponcePtr ( int iLen );
CSphSEThreadTable * GetTls ();
};
#if MYSQL_VERSION_ID < 50100
bool sphinx_show_status ( THD * thd );
#endif
int sphinx_showfunc_total_found ( THD *, SHOW_VAR *, char * );
int sphinx_showfunc_total ( THD *, SHOW_VAR *, char * );
int sphinx_showfunc_time ( THD *, SHOW_VAR *, char * );
int sphinx_showfunc_word_count ( THD *, SHOW_VAR *, char * );
int sphinx_showfunc_words ( THD *, SHOW_VAR *, char * );
//
// $Id: ha_sphinx.h 4818 2014-09-24 08:53:38Z tomat $
//