MySQL的sql语句由客户端发出,经过连接和权限验证后,最终达到服务器端,由服务器分配thread线程处理,之后就是要介绍的具体服务器端的thread线程是怎么处理每条sql语句的。【 了解thread请看后续博客或官方、各大厂分享文档】。
MySQL解析完sql以后,会生成很多item类。item类是sql解析和执行中最重要的类之一。
【Filed介绍】 MYSQL中Filed有以下几种类型: enum enum_field_types { MYSQL_TYPE_DECIMAL, MYSQL_TYPE_TINY, MYSQL_TYPE_SHORT, MYSQL_TYPE_LONG, MYSQL_TYPE_FLOAT, MYSQL_TYPE_DOUBLE, MYSQL_TYPE_NULL, MYSQL_TYPE_TIMESTAMP, MYSQL_TYPE_LONGLONG,MYSQL_TYPE_INT24, MYSQL_TYPE_DATE, MYSQL_TYPE_TIME, MYSQL_TYPE_DATETIME, MYSQL_TYPE_YEAR, MYSQL_TYPE_NEWDATE, MYSQL_TYPE_ENUM=247, MYSQL_TYPE_SET=248, MYSQL_TYPE_TINY_BLOB=249, MYSQL_TYPE_MEDIUM_BLOB=250, MYSQL_TYPE_LONG_BLOB=251, MYSQL_TYPE_BLOB=252, MYSQL_TYPE_VAR_STRING=253, MYSQL_TYPE_STRING=254, MYSQL_TYPE_GEOMETRY=255 };
【ITEM介绍】 在MYSQL中,有以下ITEM大类型: FIELD_ITEM, FUNC_ITEM, SUM_FUNC_ITEM, STRING_ITEM, INT_ITEM, REAL_ITEM, NULL_ITEM, VARBIN_ITEM, COPY_STR_ITEM, FIELD_AVG_ITEM, DEFAULT_VALUE_ITEM,
PROC_ITEM,COND_ITEM, REF_ITEM, FIELD_STD_ITEM, FIELD_VARIANCE_ITEM, INSERT_VALUE_ITEM, SUBSELECT_ITEM, ROW_ITEM, CACHE_ITEM, TYPE_HOLDER, PARAM_
ITEM其中许多ITEM还有小类,如Item_func有如下小类型: UNKNOWN_FUNC,EQ_FUNC,EQUAL_FUNC,NE_FUNC,LT_FUNC,LE_FUNC, GE_FUNC,GT_FUNC,FT_FUNC, LIKE_FUNC,NOTLIKE_FUNC,ISNULL_FUNC,ISNOTNULL_FUNC,
COND_AND_FUNC, COND_OR_FUNC, COND_XOR_FUNC, BETWEEN, IN_FUNC, INTERVAL_FUNC, ISNOTNULLTEST_FUNC, SP_EQUALS_FUNC, SP_DISJOINT_FUNC,
SP_INTERSECTS_FUNC, SP_TOUCHES_FUNC,SP_CROSSES_FUNC,SP_WITHIN_FUNC, SP_CONTAINS_FUNC,SP_OVERLAPS_FUNC, SP_STARTPOINT,SP_ENDPOINT,SP_EXTERIORRING,
SP_POINTN,SP_GEOMETRYN,SP_INTERIORRINGN, NOT_FUNC, NOT_ALL_FUNC, NOW_FUNC, VAR_VALUE_FUNC
【FIELD和ITEM的关系】 通过Item类中的tmp_table_field_from_field_type函数将一个Item类转化为一个Filed类返回。并不是所有的Item类返回的Filed都有意义,下面列举几个有意义的转化: Item_int ->Field_longlong Item_real->Field_double Item_string->Field_string
【解析结果存放实例】 例如语句select table1.field1,'test',100 from table1 where table1.field1='field1' and (table1.field2=100 or table1.field2=200) 1) 选择域的解析——“table1.field1,'test',100” 将被解析为一个List<Item> 其中List的第一个元素Item的子类Item_field,表示表中的列。 第二个元素为Item_string,表示字符串。由val_str方法可获得string值”test”,也可用tmp_table_field_from_field_type方法返回一个Field的子类Field_string的指针。 第三个元素为Item_int,表示整数。由val_int获得int值100,也可以用tmp_table_field_from_field_type方法返回一个Field的子类Field_longlong的指针。 2) Where域的解析——where table1.field1='field1' and (table1.field2=100 or table1.field2=200) 将被解析为一个Item对象,这个对象有个层次结构。 【对各类型SQL语句的解析】 MYSQL的语句类型有如下类型: enum enum_sql_command { SQLCOM_SELECT, SQLCOM_CREATE_TABLE, SQLCOM_CREATE_INDEX, SQLCOM_ALTER_TABLE, SQLCOM_UPDATE, SQLCOM_INSERT, SQLCOM_INSERT_SELECT, SQLCOM_DELETE, SQLCOM_TRUNCATE, SQLCOM_DROP_TABLE, SQLCOM_DROP_INDEX, SQLCOM_SHOW_DATABASES, SQLCOM_SHOW_TABLES, SQLCOM_SHOW_FIELDS, SQLCOM_SHOW_KEYS, SQLCOM_SHOW_VARIABLES, SQLCOM_SHOW_LOGS, SQLCOM_SHOW_STATUS, SQLCOM_SHOW_INNODB_STATUS,SQLCOM_SHOW_NDBCLUSTER_STATUS, SQLCOM_SHOW_PROCESSLIST, SQLCOM_SHOW_MASTER_STAT, SQLCOM_SHOW_SLAVE_STAT, SQLCOM_SHOW_GRANTS, SQLCOM_SHOW_CREATE, SQLCOM_SHOW_CHARSETS, SQLCOM_SHOW_COLLATIONS, SQLCOM_SHOW_CREATE_DB, SQLCOM_LOAD,SQLCOM_SET_OPTION,SQLCOM_LOCK_TABLES,SQLCOM_UNLOCK_TABLES, SQLCOM_GRANT, SQLCOM_CHANGE_DB, SQLCOM_CREATE_DB, SQLCOM_DROP_DB, SQLCOM_ALTER_DB, SQLCOM_REPAIR, SQLCOM_REPLACE, SQLCOM_REPLACE_SELECT, SQLCOM_CREATE_FUNCTION, SQLCOM_DROP_FUNCTION, SQLCOM_REVOKE,SQLCOM_OPTIMIZE, SQLCOM_CHECK, SQLCOM_ASSIGN_TO_KEYCACHE, SQLCOM_PRELOAD_KEYS, SQLCOM_FLUSH, SQLCOM_KILL, SQLCOM_ANALYZE, SQLCOM_ROLLBACK, SQLCOM_ROLLBACK_TO_SAVEPOINT, SQLCOM_COMMIT, SQLCOM_SAVEPOINT, SQLCOM_SLAVE_START, SQLCOM_SLAVE_STOP, SQLCOM_BEGIN, SQLCOM_LOAD_MASTER_TABLE, SQLCOM_CHANGE_MASTER, SQLCOM_RENAME_TABLE, SQLCOM_BACKUP_TABLE, SQLCOM_RESTORE_TABLE, SQLCOM_RESET, SQLCOM_PURGE, SQLCOM_PURGE_BEFORE, SQLCOM_SHOW_BINLOGS, SQLCOM_SHOW_OPEN_TABLES, SQLCOM_LOAD_MASTER_DATA, SQLCOM_HA_OPEN, SQLCOM_HA_CLOSE, SQLCOM_HA_READ, SQLCOM_SHOW_SLAVE_HOSTS, SQLCOM_DELETE_MULTI, SQLCOM_UPDATE_MULTI, SQLCOM_SHOW_BINLOG_EVENTS, SQLCOM_SHOW_NEW_MASTER, SQLCOM_DO, SQLCOM_SHOW_WARNS, SQLCOM_EMPTY_QUERY, SQLCOM_SHOW_ERRORS, SQLCOM_SHOW_COLUMN_TYPES, SQLCOM_SHOW_STORAGE_ENGINES, SQLCOM_SHOW_PRIVILEGES, SQLCOM_HELP, SQLCOM_DROP_USER, SQLCOM_REVOKE_ALL, SQLCOM_CHECKSUM, SQLCOM_PREPARE, SQLCOM_EXECUTE, SQLCOM_DEALLOCATE_PREPARE, SQLCOM_END }; 下文只对常用的select(SQLCOM_SELECT), update(SQLCOM_UPDATE), insert(SQLCOM_INSERT), delete(SQLCOM_DELETE)做一下介绍。 Select语句 对select类型的语句解析后,将结果存放在SELECT_LEX类中 其中: 选择域存放在SELECT_LEX::item_list中,类型为LIST<Item> where域存放在SELECT_LEX::wheret中,类型为Item* having域存放在SELECT_LEX::having中,类型为Item* order域存放在SELECT_LEX::order_list中,实际类型为ORDER* group域存放在SELECT_LEX::group_list中,实际类型为ORDER* limit域存放在SELECT_LEX::select_limit中,unsigned long table名字域存放在SELECT_LEX::table_list中,实际类型为TABLE_LIST*
Update语句 对update类型的语句解析后,将结果存放在SELECT_LEX类和LEX类中 其中: 更新域存放在SELECT_LEX::item_list中,类型为LIST<Item> 值域存放在LEX::value_list中,类型为LIST<Item> where域存放在SELECT_LEX::wheret中,类型为Item* table名字域存放在SELECT_LEX::table_list中,实际类型为TABLE_LIST* (其中更新域和值域的结构请见上文中的4(1),where域的解构请见上文中的4(2), table名字域的解构类似于链表)
Insert语句 对insert类型的语句解析后,将结果存放在SELECT_LEX类和LEX类中 其中: 插入域存放在LEX::item_list中,类型为LIST<Item> 值域存放在LEX::many_values中,类型为LIST<LIST<Item>> table名字域存放在SELECT_LEX::table_list中,实际类型为TABLE_LIST* (其中插入域的结构请见上文中的4(1), 值域可以含有多个LIST<Item>, table名字域的解构类似于链表)
Delete语句 对delete类型的语句解析后,将结果存放在SELECT_LEX类中 其中: where域存放在SELECT_LEX::wheret中,类型为Item* limit域存放在SELECT_LEX::select_limit中,unsigned long table名字域存放在SELECT_LEX::table_list中,实际类型为TABLE_LIST*
【如何使用】 由于用到了mysql的源码,必须先下载到mysql的源码,编译mysql源码,然后将makefile中的MYSQL_SRC_PATH改为实际的mysql的源码位置,然后编译。 Thd结构体: Thd{ boolean is_fatal_error select_lex lex;//select_lex … } Select_lex结构体: select_lex{ table_list;//链着所有table的链表。 sql_command;//SQLCOM_SELECT、SQLCOM_DELETE、SQLCOM_INSERT、SQLCOM_UPDATE … } 所用到的文件: 其中parse_base.cpp是对mysql源码的一个简单的封装,test_parse.cpp中是需要编写修改的代码。重要的部分介绍: // yyparse是用yacc对sql进行解析 if (!yyparse((void *)&thd) && ! thd.is_fatal_error){ if(thd.lex == NULL || thd.lex->select_lex.table_list.first == NULL) { cout<<"内部错误"<<endl; iRet = -1; } else { //获取LEX和SELECT_LEX对象 LEX *lex= thd.lex; SELECT_LEX *select_lex= &lex->select_lex; //打印table的名字 TABLE_LIST* tables= (TABLE_LIST*) select_lex->table_list.first; if(tables != NULL) { cout<<"table name:"<<tables->real_name<<endl; } enum_sql_command command_type; command_type = lex->sql_command; switch(command_type) { case SQLCOM_SELECT: //选择 break; case SQLCOM_DELETE: //删除 break; case SQLCOM_INSERT: //插入 break; case SQLCOM_UPDATE: //更新 break; default: //其他 iRet = -1; } }
对sql进行优化处理。 【例如select语句的优化具体是在JOIN::optimise函数中完成。(MySQL针对select的处理是转换成JOIN操作处理的)】 select A.id, B.score from student A left join subject B on A.id=B.id where A.age > 10 and B.score > 60; 优化过程会将join的key也转换为一个where条件,经过处理后,上面的sql就有了3个where条件: A.age > 10; A.id = B.id; B.score > 60; sql执行 例如select语句的执行具体是在JOIN::exec(MySQL是将任何select都转换为JOIN来处理的)。即JOIN::exec函数,首先会调用send_fields函数,将最终结果的信息返回,
然后调用do_select。在do_select函数中,通过调用sub_select函数来具体实现join功能。