MYSQL的启动

MYSQL的启动

主程序是在mysqld.cc这个文件,入口是win_main,或者是mysqld_main()这个函数

 初始化,包括pthreads线程和系统库。在line #4359附近的地方。

if (my_init()) // init my_sys library & pthreads

  {

    sql_print_error("my_init() failed.");

    flush_error_log_messages();

    return 1;

  }

第二步,读配置文件

if (load_defaults(MYSQL_CONFIG_NAME, load_default_groups, &argc, &argv))

  {

    flush_error_log_messages();

    return 1;

  }

第三步:登记Performance Schema

 第四步:初始化init_error_log() 和 query_logger.init()

定位data_dir目录,即数据文件路径。

如果启用了binlog,则必须提供server-id

 初始化init_SSL()和初始化网络 network_init()

 产生一个PID文件。

=========

每个线程处理命令的函数为:

bool do_command(THD *thd) 

{

//从网络协议中,获得待执行的命令

rc= thd->get_protocol()->get_command(&com_data, &command);

       //派遣命令

       return_value= dispatch_command(thd, &com_data, command);

 }

  

bool dispatch_command(THD *thd, const COM_DATA *com_data,

                      enum enum_server_command command)

{

//开始执行命令

  /* DTRACE instrumentation, begin */

  MYSQL_COMMAND_START(thd->thread_id(), command,

                      (char *) thd->security_context()->priv_user().str,

                      (char *) thd->security_context()->host_or_ip().str);

}

如何排查一个查询语句的表:

0:006> dv

            thd = 0x00000000`0e2c4b90

   parser_state = 0x00000000`0e2c4b90

0:006> dt thd

Local var @ 0xf80ec60 Type THD*

0x00000000`0e2c4b90

   +0x000 __VFN_table : 0x00000001`40a507b8

   +0x008 __VFN_table : 0x00000001`40a50810

   +0x010 free_list        : 0x00000000`0dfd0e08 Item

   +0x018 mem_root         : 0x00000000`0e2c7268 st_mem_root

   +0x020 state            : 3 ( STMT_CONVENTIONAL_EXECUTION )

   +0x028 m_reprepare_observers : Prealloced_array<Reprepare_observer *,4,1>

   +0x068 open_tables      : (null)

   +0x070 temporary_tables : (null)

   +0x078 derived_tables   : (null)

   +0x080 lock             : (null)

   +0x088 extra_lock       : (null)

   +0x090 locked_tables_mode : 0 ( LTM_NONE )

   +0x094 state_flags      : 0

   +0x098 mdl_context      : MDL_context

   +0x180 mark_used_columns : 1 ( MARK_COLUMNS_READ )

   +0x184 want_privilege   : 0xbfffffff

   +0x188 lex              : 0x00000000`0e2c6888 LEX

  

  

0:006> dt 0x00000000`0e2c6888 LEX

mysqld!LEX

   +0x008 sql_command      : 0 ( SQLCOM_SELECT )

   +0x010 query_tables     : 0x00000000`0dfd11c0 TABLE_LIST

0:006> dt 0x00000000`0dfd11c0 TABLE_LIST

mysqld!TABLE_LIST

   +0x000 next_local       : (null)

   +0x008 next_global      : (null)

   +0x010 prev_global      : 0x00000000`0e2c6898  -> 0x00000000`0dfd11c0 TABLE_LIST

   +0x018 db               : 0x00000000`0dfd1738  "sakila"

   +0x020 table_name       : 0x00000000`0dfd0930  "country"

   +0x028 alias            : 0x00000000`0dfd11b8  "country"

   +0x030 target_tablespace_name : st_mysql_const_lex_string

   +0x040 schema_table_name : (null)

   +0x048 option           : (null)

 

thd有一个成员变量:是用于存放查询字符串的。

   +0x198 m_query_string   : st_mysql_const_lex_string

查询方式如下:在MYSQL_PARSE()的地方,稍微往下走几步。否则显示不出来。

0:006> dv

            thd = 0x00000000`0e2c4b90

   parser_state = 0x00000000`0e2c4b90

0:006> dt thd+0x198 st_mysql_const_lex_string

mysqld!st_mysql_const_lex_string

   +0x000 str              : 0x00000000`0dfcfc18  ""

   +0x008 length           : 0xdfcfbd0

0:006> db 0x00000000`0dfcfc18

00000000`0dfcfc18  00 fe fc 0d 00 00 00 00-73 65 6c 65 63 74 20 63  ........select c

00000000`0dfcfc28  6f 75 6e 74 72 79 5f 69-64 2c 20 63 6f 75 6e 74  ountry_id, count

00000000`0dfcfc38  72 79 20 66 72 6f 6d 20-63 6f 75 6e 74 72 79 20  ry from country

00000000`0dfcfc48  77 68 65 72 65 20 63 6f-75 6e 74 72 79 20 6c 69  where country li

00000000`0dfcfc58  6b 65 20 27 61 6e 25 27-20 6c 69 6d 69 74 20 35  ke 'an%' limit 5

00000000`0dfcfc68  00 00 00 00 00 00 00 00-c0 64 a5 40 01 00 00 00  .........d.@....

00000000`0dfcfc78  00 00 00 00 00 00 00 00-68 ff fc 0d 00 00 00 00  ........h.......

00000000`0dfcfc88  50 ff fc 0d 00 00 00 00-00 00 00 00 00 00 00 00  P...............

  

数据库记录中的页(Page)信息。

这个记录是逻辑页:

0:006> dt dtuple_t

mysqld!dtuple_t

   +0x000 info_bits        : Uint8B

   +0x008 n_fields         : Uint8B

   +0x010 n_fields_cmp     : Uint8B

   +0x018 fields           : Ptr64 dfield_t

   +0x020 n_v_fields       : Uint8B

   +0x028 v_fields         : Ptr64 dfield_t

   +0x030 tuple_list       : ut_list_node<dtuple_t>

 

 

 

/********************************************************************//**

Positions a cursor on the first record in an index and reads the corresponding row to buf.

@return 0, HA_ERR_END_OF_FILE, or error code */

 

int

ha_innobase::index_first(

      uchar*      buf)  /*!< in/out: buffer for the row */

{

      DBUG_ENTER("index_first");

      ha_statistic_increment(&SSV::ha_read_first_count);

      int   error = index_read(buf, NULL, 0, HA_READ_AFTER_KEY);

      /* MySQL does not seem to allow this to return HA_ERR_KEY_NOT_FOUND */

      if (error == HA_ERR_KEY_NOT_FOUND) {

            error = HA_ERR_END_OF_FILE;

      }

      DBUG_RETURN(error);

}

MySQL的SELECT语句执行在innobase ow ow0sel.cc这个文件中。

Do_select(); 查询入口函数

| Sub_SELECT(); 查询部分JOIN的记录。循环调用ha_innobase::rnd_next()和evaluate_join_record() 获取并处理该部分的每条记录。

|| evaluate_join_record(): 处理一条查询记录。

|| rr_sequential(); 调用ha_innobase::rnd_next()读取下一条记录。

||| ha_innobase::rnd_next(): 读取下一条记录。

|||| ha_innobase::general_fetch(); 从给定的索引位置获取下一条或上一条记录

||||| row_search_for_mysql():从数据库中查询一条记录。以下分为六个阶段分别处理各个部分。

|||||| 第一阶段: 释放自适应hash索引的锁

||||||| rw_lock_get_writer() 函数用于获取读写锁,如果获取失败,释放目前的读写锁

|||||| 第二阶段:从预读的cache中获取记录

||||||| row_sel_pop_cached_row_for_mysql(); 函数用于从cache中读取一行记录。

|||||||| row_sel_copy_cached_field_for_mysql(); 函数读取每个字段。

|||||| 第三阶段:使用自适应hash索引快速查找

||||||| row_sel_try_search_shortcut_for_mysql() 函数使用hash索引获取聚集索引的记录

|||||||| row_sel_store_mysql_rec() 函数将获取的innobase格式行记录转化为mysql格式

||||||||| row_sel_field_store_in_mysql_format() 函数将innobase格式的行记录中的每个字段转化为mysql格式

|||||| 第四阶段:打开并恢复索引的游标位置

||||||| sel_restore_position_for_mysql(); 恢复索引的游标位置

|||||||| btr_pcur_restore_position_func(): 恢复一个持久化游标的位置

||||||||| btr_cur_get_index(); 获取索引

||||||||| buf_page_optimistic_get()

||||||||| btr_pcur_get_rec() 获取持久化游标的记录

|||||||||| btr_cur_get_rec(); 获取当前游标位置的记录

||||||||| rec_get_offsets_func(): 获取记录中每个字段的偏移

|||||||| btr_pcur_move_to_next(); 移动持久化游标到下一条记录

|||||| 第五阶段:查找匹配的记录

||||||| page_rec_is_infimum(): 查看当前记录是否是该页的infinum记录。Infinum记录表示比任何键值都小的记录

||||||| page_rec_is_supernum(); 查看当前记录是否是该页的supermum记录,supermum记录表示比任何键值都大的记录。

||||||| rec_get_next_offs(): 获取相同页中下一条记录的偏移量。

||||||| rec_get_offsets_func(): 获取记录中每个字段的便宜

||||||| rec_offs_validate() 验证记录的偏移量

||||||| row_sel_store_mysql_rec() 函数将获取的innobase格式的行记录转化为mysql格式

|||||||| row_sel_field_store_in_mysql_format() 函数将innobase格式的行记录中的每个字段转化为mysql格式

|||||||| btr_pcur_store_position*(: 存储游标的位置

||||||||| btr_pcur_get_block(): 获取持久化游标的缓冲块

||||||||| btr_pcur_get_page_cur(): 获取持久化游标的页的游标

||||||||| page_cur_get_rec(): 获取游标位置的记录

||||||||| dict_index_copy_rec_order_prefix(): 拷贝记录

|||||||||| rec_copy_prefix_to_buf(): 拷贝记录的字段到缓存buffer中

|||||||||| dict_index_get_nth_field(): 获取第n个字段的起始地址。

|||||||||| dict_field_get_col(): 获取第n个字段的值

|||||| 第六阶段:移动游标到下一个索引记录

||||||| btr_pcur_move_to_next(): 移动持久化游标到下一条记录

||||||| mtr_commit(): 提交事务

  

参考资料:http://www.it165.net/database/html/201208/2857.html

原文地址:https://www.cnblogs.com/rgyu/p/7534077.html