2、SQL的生命週期

  MySQL的sql語句由客戶端發出,通過鏈接和權限驗證後,最終達到服務器端,由服務器分配thread線程處理,以後就是要介紹的具體服務器端的thread線程是怎麼處理每條sql語句的。【 瞭解thread請看後續博客或官方、各大廠分享文檔】。python

一、SQL解析mysql

二、SQL MySQL內部優化與執行sql

 

一、服務器

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功能。
相關文章
相關標籤/搜索