mirror of
https://github.com/MariaDB/server.git
synced 2025-01-30 02:30:06 +01:00
d9d0e78039
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.
189 lines
5.6 KiB
C++
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 $
|
|
//
|