MySQL数据库中使用use来切换数据库之底层原理

【MySQL源码】use database

    • 切换表空间
    • 切换表空间源码分析
      • 客户端流程
      • 服务端流程

说明:
以下所有说明都以 MySQL 5.7.25 源码为例 ,存储引擎为InnoDB。

切换表空间

mysql客户端登录之后,需要使用use database_name选取表空间并切换到具体的表空间下进行操作,否则会报错:
使用前未使用use database_name

mysql>show tables;
ERROR 1046 (3D000): No database selected

选取并切换:

mysql>use test;
mysql>show tables;
+-----------------+
| Tables_in_test  |
+-----------------+
| t1              |
| t2              |
+-----------------+
2 rows in set (0.00 sec)

切换表空间源码分析

客户端流程

在mysql客户端上执行use database_name,其实背后是一套组合的操作命令,大概的主要操作流程为;

  • 通过SELECT DATABASE()获取当前的database的名称;
  • 比较use database_name中的namecurrent_db_name是否一致;
  • 不一致则通过show databases查询所有的databases并且校验选择use database_name中对应的database;
  • 通过show tables打开所有的tables;
mysql_client
com_use(String *buffer MY_ATTRIBUTE((unused)), char *line)
  get_current_db();
  >get_current_db
    if !mysql_query(&mysql, "SELECT DATABASE()") && res=mysql_use_result(&mysql)
      MYSQL_ROW = mysql_fetch_row(res)
      if row && row[0]
        current_db = my_strdup(PSI_NOT_INSTRUMENTED, row[0], MYF(MY_WME))
        mysql_free_result(res)
      fi
    fi
  <get_current_db
  if !current_db || cmp_database(charset_info, current_db, tmp) //current_db="innodb", tmp="ywx"
  fi
  
  if select_db; THEN//select_db = 2
    if mysql_select_db(&mysql, tmp)
    fi
    my_free(current_db)
    current_db = my_strdup(PSI_NOT_INSTRUMENTED, tmp, MYF(MY_WME)
  fi
  if (select_db > 1)
      build_completion_hash(opt_rehash, 1)
      >build_completion_hash
        if (mysql_query(&mysql,"show databases") == 0)// "show databasess"
        fi
        if (mysql_query(&mysql,"show tables")==0)//"show tables"
          if !(tables = mysql_store_result(&mysql))
          else
            while table_row=mysql_fetch_row(tables)
            do
            done             
          fi
        fi
      <build_completion_hash
  fi

服务端流程

服务端对应客户端不同阶段的请求处理为:

  • 处理SELECT DATABASE()请求;
    SELECT DATABASE()走的是SELECT流程,DATABASE()作为一个function的形式进行处理,其yacc语法规则为:
function_call_conflict:
	ASCII_SYM '(' expr ')'
	{
	  $$= NEW_PTN Item_func_ascii(@$, $3);
	}
	...
	| DATABASE '(' ')'
	{
	  $$= NEW_PTN Item_func_database(@$);
	}
  • 处理show databases请求, yacc语法规则为:
show:
  SHOW
  {
    LEX *lex=Lex;
    new (&lex->create_info) HA_CREATE_INFO;
  }
  show_param
  ;
show_param:
  DATABASES opt_wild_or_where
  {
     LEX *lex= Lex;
     lex->sql_command= SQLCOM_SHOW_DATABASES;
     if (prepare_schema_table(YYTHD, lex, 0, SCH_SCHEMATA))
       MYSQL_YYABORT;
  }
  • 处理show tablesyacc语法规则为:
show:
  SHOW
  {
    LEX *lex=Lex;
    new (&lex->create_info) HA_CREATE_INFO;
  }
  show_param
  ;
show_param:
 | opt_full TABLES opt_db opt_wild_or_where
   {
     LEX *lex= Lex;
     lex->sql_command= SQLCOM_SHOW_TABLES;
     lex->select_lex->db= $3;
     if (prepare_schema_table(YYTHD, lex, 0, SCH_TABLE_NAMES))
       MYSQL_YYABORT;
   }
mysql_execute_command
  switch lex->sql_command:
  case SQLCOM_SHOW_DATABASES:
  case SQLCOM_SHOW_TABLES:
  case SQLCOM_SELECT:
    res= execute_sqlcom_select(thd, all_tables)
    >execute_sqlcom_select
      if !open_tables_for_query(thd, all_tables, 0); THEN
        if lex->is_explain(); THEN
          Query_result *const result= new Query_result_send
          res= handle_query(thd, lex, result, 0, 0)
        else
          res= handle_query(thd, lex, result, 0, 0)
        fi
      fi
    <execute_sqlcom_select
handle_query
  const bool single_query= unit->is_simple()
  //phase 1: prepare
  if single_query; THEN
    unit->set_limit(unit->global_parameters())
    select->context.resolve_in_select_list= true
    select->set_query_result(result)
    select->make_active_options(added_options, removed_options)
    select->fields_list= select->item_list
    if select->prepare(thd); THEN
    fi
    unit->set_prepared()
  ELSE
    if unit->prepare(thd, result, SELECT_NO_UNLOCK | added_options, removed_options); THEN
    fi
  fi
  if lock_tables(thd, lex->query_tables, lex->table_count, 0); THEN
  fi
  //register query result in cache
  query_cache.store_query(thd, lex->query_tables)
  
  //phase 2: optimize
  if single_query; THEN
    if select->optimize(thd); THEN
    fi
    unit->set_optimized()
  ELSE
    if select->optimize(thd); THEN
    fi
  fi
  
  //phase 3: execute
  if lex->is_explain(); THEN
    if explain_query(thd, unit); THEN
    fi
  ELSE
    if single_query; THEN
      select->join->exec()
      unit->set_executed()
      if thd->is_error() ; THEN
        goto err;
    else
      if (unit->execute(thd)); THEN
        goto err;
  fi
  res= unit->cleanup(false)

你可能感兴趣的:(MySQL,MySQL,源码解析,use,tables)